Fix for assertion error when expanding macro.
[iverilog.git] / elab_net.cc
blobb97a9c8b7aa82e31cce1a93ce4e27d3f4710cd60
1 /*
2 * Copyright (c) 1999-2007 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: elab_net.cc,v 1.207 2007/06/12 04:05:45 steve Exp $"
21 #endif
23 # include "config.h"
25 # include "PExpr.h"
26 # include "netlist.h"
27 # include "netmisc.h"
28 # include "compiler.h"
30 # include <iostream>
31 # include "ivl_assert.h"
34 * This is a state flag that determines whether an elaborate_net must
35 * report an error when it encounters an unsized number. Normally, it
36 * is fine to make an unsized number as small as it can be, but there
37 * are a few cases where the size must be fully self-determined. For
38 * example, within a {...} (concatenation) operator.
40 static bool must_be_self_determined_flag = false;
42 NetNet* PExpr::elaborate_net(Design*des, NetScope*scope, unsigned,
43 const NetExpr*,
44 const NetExpr*,
45 const NetExpr*,
46 Link::strength_t,
47 Link::strength_t) const
49 cerr << get_line() << ": error: Unable to elaborate `"
50 << *this << "' as gates." << endl;
51 return 0;
55 * Elaborating binary operations generally involves elaborating the
56 * left and right expressions, then making an output wire and
57 * connecting the lot together with the right kind of gate.
59 NetNet* PEBinary::elaborate_net(Design*des, NetScope*scope,
60 unsigned width,
61 const NetExpr* rise,
62 const NetExpr* fall,
63 const NetExpr* decay,
64 Link::strength_t drive0,
65 Link::strength_t drive1) const
67 switch (op_) {
68 case '*':
69 return elaborate_net_mul_(des, scope, width, rise, fall, decay);
70 case '%':
71 return elaborate_net_mod_(des, scope, width, rise, fall, decay);
72 case '/':
73 return elaborate_net_div_(des, scope, width, rise, fall, decay);
74 case '+':
75 case '-':
76 return elaborate_net_add_(des, scope, width, rise, fall, decay);
77 case '|': // Bitwise OR
78 case '&':
79 case '^':
80 case 'A': // Bitwise NAND (~&)
81 case 'O': // Bitwise NOR (~|)
82 case 'X': // Exclusive NOR
83 return elaborate_net_bit_(des, scope, width, rise, fall, decay);
84 case 'E': // === (case equals)
85 case 'e': // ==
86 case 'N': // !== (case not-equals)
87 case 'n': // !=
88 case '<':
89 case '>':
90 case 'L': // <=
91 case 'G': // >=
92 return elaborate_net_cmp_(des, scope, width, rise, fall, decay);
93 case 'a': // && (logical and)
94 case 'o': // || (logical or)
95 return elaborate_net_log_(des, scope, width, rise, fall, decay);
96 case 'l': // <<
97 case 'r': // >>
98 case 'R': // >>>
99 return elaborate_net_shift_(des, scope, width, rise, fall, decay);
102 NetNet*lsig = left_->elaborate_net(des, scope, width, 0, 0, 0),
103 *rsig = right_->elaborate_net(des, scope, width, 0, 0, 0);
104 if (lsig == 0) {
105 cerr << get_line() << ": error: Cannot elaborate ";
106 left_->dump(cerr);
107 cerr << endl;
108 return 0;
110 if (rsig == 0) {
111 cerr << get_line() << ": error: Cannot elaborate ";
112 right_->dump(cerr);
113 cerr << endl;
114 return 0;
117 NetNet*osig;
119 switch (op_) {
120 case '^': // XOR
121 case 'X': // XNOR
122 case '&': // AND
123 case '|': // Bitwise OR
124 assert(0);
125 break;
127 case 'E': // === (Case equals)
128 case 'e': // ==
129 case 'n': // !=
130 case '<':
131 case '>':
132 case 'G': // >=
133 case 'L': // <=
134 assert(0);
135 break;
137 case '+':
138 assert(0);
139 break;
141 case 'l':
142 case 'r':
143 case 'R':
144 assert(0);
145 break;
146 default:
147 cerr << get_line() << ": internal error: unsupported"
148 " combinational operator (" << op_ << ")." << endl;
149 des->errors += 1;
150 osig = 0;
153 return osig;
157 * Elaborate the structural +/- as an AddSub object. Connect DataA and
158 * DataB to the parameters, and connect the output signal to the
159 * Result. In this context, the device is a combinational adder with
160 * fixed direction, so leave Add_Sub unconnected and set the
161 * LPM_Direction property.
163 NetNet* PEBinary::elaborate_net_add_(Design*des, NetScope*scope,
164 unsigned lwidth,
165 const NetExpr* rise,
166 const NetExpr* fall,
167 const NetExpr* decay) const
169 NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0),
170 *rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
171 if (lsig == 0) {
172 cerr << get_line() << ": error: Cannot elaborate ";
173 left_->dump(cerr);
174 cerr << endl;
175 return 0;
177 if (rsig == 0) {
178 cerr << get_line() << ": error: Cannot elaborate ";
179 right_->dump(cerr);
180 cerr << endl;
181 return 0;
184 NetNet*osig;
186 unsigned width = lsig->vector_width();
187 if (rsig->vector_width() > lsig->vector_width())
188 width = rsig->vector_width();
191 /* The owidth is the output width of the lpm_add_sub
192 device. If the desired width is greater then the width of
193 the operands, then widen the adder and let code below pad
194 the operands. */
195 unsigned owidth = width;
196 switch (op_) {
197 case '+':
198 if (lwidth > owidth) {
199 owidth = lwidth;
200 width = lwidth;
202 break;
203 case '-':
204 if (lwidth > owidth) {
205 owidth = lwidth;
206 width = lwidth;
208 break;
209 default:
210 assert(0);
213 bool expr_signed = lsig->get_signed() && rsig->get_signed();
215 // Pad out the operands, if necessary, the match the width of
216 // the adder device.
217 if (lsig->vector_width() < width)
218 if (expr_signed)
219 lsig = pad_to_width_signed(des, lsig, width);
220 else
221 lsig = pad_to_width(des, lsig, width);
223 if (rsig->vector_width() < width)
224 if (expr_signed)
225 rsig = pad_to_width_signed(des, rsig, width);
226 else
227 rsig = pad_to_width(des, rsig, width);
229 // Check that the argument types match.
230 if (lsig->data_type() != rsig->data_type()) {
231 cerr << get_line() << ": error: Arguments of add/sub "
232 << "have different data types." << endl;
233 cerr << get_line() << ": : Left argument is "
234 << lsig->data_type() << ", right argument is "
235 << rsig->data_type() << "." << endl;
236 des->errors += 1;
239 // Make the adder as wide as the widest operand
240 osig = new NetNet(scope, scope->local_symbol(),
241 NetNet::WIRE, owidth);
242 osig->data_type(lsig->data_type());
243 osig->set_signed(expr_signed);
244 osig->local_flag(true);
245 if (debug_elaborate) {
246 cerr << get_line() << ": debug: Elaborate NetAddSub "
247 << "width=" << width << " lwidth=" << lwidth
248 << endl;
250 NetAddSub*adder = new NetAddSub(scope, scope->local_symbol(), width);
252 // Connect the adder to the various parts.
253 connect(lsig->pin(0), adder->pin_DataA());
254 connect(rsig->pin(0), adder->pin_DataB());
255 connect(osig->pin(0), adder->pin_Result());
256 #ifdef XXXX
257 if (owidth > width)
258 connect(osig->pin(width), adder->pin_Cout());
259 #endif
260 NetNode*gate = adder;
261 gate->rise_time(rise);
262 gate->fall_time(fall);
263 gate->decay_time(decay);
264 des->add_node(gate);
266 gate->attribute(perm_string::literal("LPM_Direction"),
267 verinum(op_ == '+' ? "ADD" : "SUB"));
269 return osig;
273 * Elaborate various bitwise logic operators. These are all similar in
274 * that they take operants of equal width, and each bit does not
275 * affect any other bits. Also common about all this is how bit widths
276 * of the operands are handled, when they do not match.
278 NetNet* PEBinary::elaborate_net_bit_(Design*des, NetScope*scope,
279 unsigned width,
280 const NetExpr* rise,
281 const NetExpr* fall,
282 const NetExpr* decay) const
284 NetNet*lsig = left_->elaborate_net(des, scope, width, 0, 0, 0),
285 *rsig = right_->elaborate_net(des, scope, width, 0, 0, 0);
286 if (lsig == 0) {
287 cerr << get_line() << ": error: Cannot elaborate ";
288 left_->dump(cerr);
289 cerr << endl;
290 return 0;
292 if (rsig == 0) {
293 cerr << get_line() << ": error: Cannot elaborate ";
294 right_->dump(cerr);
295 cerr << endl;
296 return 0;
299 if (lsig->vector_width() < rsig->vector_width())
300 lsig = pad_to_width(des, lsig, rsig->vector_width());
301 if (rsig->vector_width() < lsig->vector_width())
302 rsig = pad_to_width(des, rsig, lsig->vector_width());
304 if (lsig->data_type() != rsig->data_type()) {
305 cerr << get_line() << ": error: Types of "
306 << "operands of " << op_ << " do not match: "
307 << lsig->data_type() << " vs. " << rsig->data_type()
308 << endl;
309 des->errors += 1;
310 return 0;
313 if (lsig->vector_width() != rsig->vector_width()) {
314 cerr << get_line() << ": internal error: lsig width ("
315 << lsig->vector_width() << ") != rsig pin width ("
316 << rsig->vector_width() << ")." << endl;
317 des->errors += 1;
318 return 0;
321 assert(lsig->vector_width() == rsig->vector_width());
323 NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE,
324 lsig->vector_width());
325 osig->local_flag(true);
326 osig->data_type( lsig->data_type() );
328 NetLogic::TYPE gtype=NetLogic::AND;
329 switch (op_) {
330 case '^': gtype = NetLogic::XOR; break; // XOR
331 case 'X': gtype = NetLogic::XNOR; break; // XNOR
332 case '&': gtype = NetLogic::AND; break; // AND
333 case 'A': gtype = NetLogic::NAND; break; // NAND (~&)
334 case '|': gtype = NetLogic::OR; break; // Bitwise OR
335 case 'O': gtype = NetLogic::NOR; break; // Bitwise NOR
336 default: assert(0);
339 NetLogic*gate = new NetLogic(scope, scope->local_symbol(),
340 3, gtype, osig->vector_width());
341 gate->set_line(*this);
342 connect(gate->pin(0), osig->pin(0));
343 connect(gate->pin(1), lsig->pin(0));
344 connect(gate->pin(2), rsig->pin(0));
345 gate->rise_time(rise);
346 gate->fall_time(fall);
347 gate->decay_time(decay);
348 des->add_node(gate);
350 return osig;
354 * This function attempts to handle the special case of == or !=
355 * compare to a constant value. The caller has determined already that
356 * one of the operands is a NetEConst, and has already elaborated the
357 * other.
359 static NetNet* compare_eq_constant(Design*des, NetScope*scope,
360 NetNet*lsig, NetEConst*rexp,
361 char op_code,
362 const NetExpr* rise,
363 const NetExpr* fall,
364 const NetExpr* decay)
366 if (op_code != 'e' && op_code != 'n')
367 return 0;
369 verinum val = rexp->value();
371 /* Abandon special case if there are x or z bits in the
372 constant. We can't get the right behavior out of
373 OR/NOR in this case. */
374 if (! val.is_defined())
375 return 0;
377 if (val.len() < lsig->vector_width())
378 val = verinum(val, lsig->vector_width());
380 /* Look for the very special case that we know the compare
381 results a priori due to different high bits, that are
382 constant pad in the signal. */
383 if (val.len() > lsig->vector_width()) {
384 unsigned idx = lsig->vector_width();
385 verinum::V lpad = verinum::V0;
387 while (idx < val.len()) {
388 if (val.get(idx) != lpad) {
389 verinum oval (op_code == 'e'
390 ? verinum::V0
391 : verinum::V1,
393 NetEConst*ogate = new NetEConst(oval);
394 NetNet*osig = ogate->synthesize(des);
395 osig->data_type(lsig->data_type());
396 delete ogate;
398 if (debug_elaborate)
399 cerr << lsig->get_line() << ": debug: "
400 << "Equality replaced with "
401 << oval << " due to high pad mismatch"
402 << endl;
404 return osig;
407 idx +=1;
411 unsigned zeros = 0;
412 unsigned ones = 0;
413 for (unsigned idx = 0 ; idx < lsig->vector_width() ; idx += 1) {
414 if (val.get(idx) == verinum::V0)
415 zeros += 1;
416 if (val.get(idx) == verinum::V1)
417 ones += 1;
420 /* Handle the special case that the gate is a compare that can
421 be replaces with a reduction AND or NOR. */
423 if (ones == 0 || zeros == 0) {
424 NetUReduce::TYPE type;
426 if (zeros > 0) {
427 type = op_code == 'e'? NetUReduce::NOR : NetUReduce::OR;
429 if (debug_elaborate)
430 cerr << lsig->get_line() << ": debug: "
431 << "Replace net==" << val << " equality with "
432 << zeros << "-input reduction [N]OR gate." << endl;
434 } else {
435 type = op_code == 'e'? NetUReduce::AND : NetUReduce::NAND;
437 if (debug_elaborate)
438 cerr << lsig->get_line() << ": debug: "
439 << "Replace net==" << val << " equality with "
440 << ones << "-input reduction AND gate." << endl;
443 NetUReduce*red = new NetUReduce(scope, scope->local_symbol(),
444 type, zeros+ones);
445 des->add_node(red);
446 red->set_line(*lsig);
448 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
449 NetNet::WIRE, 0, 0);
450 tmp->data_type(lsig->data_type());
451 tmp->local_flag(true);
452 tmp->set_line(*lsig);
454 connect(red->pin(1), lsig->pin(0));
455 connect(red->pin(0), tmp->pin(0));
456 return tmp;
459 if (debug_elaborate)
460 cerr << lsig->get_line() << ": debug: "
461 << "Give up trying to replace net==" << val
462 << " equality with "
463 << ones << "-input AND and "
464 << zeros << "-input NOR gates." << endl;
466 return 0;
470 * Elaborate the various binary comparison operators. The comparison
471 * operators return a single bit result, no matter what, so the left
472 * and right values can have their own size. The only restriction is
473 * that they have the same size.
475 NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
476 unsigned lwidth,
477 const NetExpr* rise,
478 const NetExpr* fall,
479 const NetExpr* decay) const
482 /* Elaborate the operands of the compare first as expressions
483 (so that the eval_tree method can reduce constant
484 expressions, including parameters) then turn those results
485 into synthesized nets. */
486 NetExpr*lexp = elab_and_eval(des, scope, left_, lwidth);
487 if (lexp == 0) {
488 cerr << get_line() << ": error: Cannot elaborate ";
489 left_->dump(cerr);
490 cerr << endl;
491 return 0;
494 NetExpr*rexp = elab_and_eval(des, scope, right_, lwidth);
495 if (rexp == 0) {
496 cerr << get_line() << ": error: Cannot elaborate ";
497 right_->dump(cerr);
498 cerr << endl;
499 return 0;
502 /* Choose the operand width to be the width of the widest
503 self-determined operand. */
504 unsigned operand_width = lexp->expr_width();
505 if (rexp->expr_width() > operand_width)
506 operand_width = rexp->expr_width();
508 lexp->set_width(operand_width);
509 lexp = pad_to_width(lexp, operand_width);
510 rexp->set_width(operand_width);
511 rexp = pad_to_width(rexp, operand_width);
513 NetNet*lsig = 0;
514 NetNet*rsig = 0;
516 /* Handle the special case that the right or left
517 sub-expression is a constant value. The compare_eq_constant
518 function will return an elaborated result if it can make
519 use of the situation, or 0 if it cannot. */
520 if (NetEConst*tmp = dynamic_cast<NetEConst*>(rexp)) {
522 lsig = lexp->synthesize(des);
523 if (lsig == 0) {
524 cerr << get_line() << ": internal error: "
525 "Cannot elaborate net for " << *lexp << endl;
526 return 0;
528 assert(lsig);
529 delete lexp;
530 lexp = 0;
532 NetNet*osig = compare_eq_constant(des, scope,
533 lsig, tmp, op_,
534 rise, fall, decay);
535 if (osig != 0) {
536 delete rexp;
537 return osig;
541 if (NetEConst*tmp = dynamic_cast<NetEConst*>(lexp)) {
543 rsig = rexp->synthesize(des);
544 assert(rsig);
545 delete rexp;
547 NetNet*osig = compare_eq_constant(des, scope,
548 rsig, tmp, op_,
549 rise, fall, decay);
550 if (osig != 0) {
551 delete lexp;
552 return osig;
556 if (lsig == 0) {
557 lsig = lexp->synthesize(des);
558 assert(lsig);
559 delete lexp;
562 if (rsig == 0) {
563 rsig = rexp->synthesize(des);
564 assert(rsig);
565 delete rexp;
568 unsigned dwidth = lsig->vector_width();
569 if (rsig->vector_width() > dwidth) dwidth = rsig->vector_width();
571 /* Operands of binary compare need to be padded to equal
572 size. Figure the pad bit needed to extend the narrowest
573 vector. */
574 if (lsig->vector_width() < dwidth)
575 lsig = pad_to_width(des, lsig, dwidth);
576 if (rsig->vector_width() < dwidth)
577 rsig = pad_to_width(des, rsig, dwidth);
580 NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE);
581 osig->data_type(IVL_VT_LOGIC);
582 osig->set_line(*this);
583 osig->local_flag(true);
585 NetNode*gate;
587 switch (op_) {
588 case '<':
589 case '>':
590 case 'L':
591 case 'G': {
592 NetCompare*cmp = new
593 NetCompare(scope, scope->local_symbol(), dwidth);
594 connect(cmp->pin_DataA(), lsig->pin(0));
595 connect(cmp->pin_DataB(), rsig->pin(0));
597 switch (op_) {
598 case '<':
599 connect(cmp->pin_ALB(), osig->pin(0));
600 break;
601 case '>':
602 connect(cmp->pin_AGB(), osig->pin(0));
603 break;
604 case 'L':
605 connect(cmp->pin_ALEB(), osig->pin(0));
606 break;
607 case 'G':
608 connect(cmp->pin_AGEB(), osig->pin(0));
609 break;
611 /* If both operands are signed, then do a signed
612 compare. */
613 if (lsig->get_signed() && rsig->get_signed())
614 cmp->set_signed(true);
616 gate = cmp;
617 break;
620 case 'E': // Case equals (===)
621 gate = new NetCaseCmp(scope, scope->local_symbol(), dwidth, true);
622 connect(gate->pin(0), osig->pin(0));
623 connect(gate->pin(1), lsig->pin(0));
624 connect(gate->pin(2), rsig->pin(0));
625 break;
627 case 'N': // Case equals (!==)
628 gate = new NetCaseCmp(scope, scope->local_symbol(), dwidth, false);
629 connect(gate->pin(0), osig->pin(0));
630 connect(gate->pin(1), lsig->pin(0));
631 connect(gate->pin(2), rsig->pin(0));
632 break;
634 case 'e': // ==
636 /* Handle the special case of single bit compare with a
637 single XNOR gate. This is easy and direct. */
638 if (dwidth == 1) {
639 gate = new NetLogic(scope, scope->local_symbol(),
640 3, NetLogic::XNOR, 1);
641 connect(gate->pin(0), osig->pin(0));
642 connect(gate->pin(1), lsig->pin(0));
643 connect(gate->pin(2), rsig->pin(0));
644 break;
647 if (debug_elaborate) {
648 cerr << get_line() << ": debug: Elaborate net == gate."
649 << endl;
652 /* Oh well, do the general case with a NetCompare. */
653 { NetCompare*cmp = new NetCompare(scope, scope->local_symbol(),
654 dwidth);
655 connect(cmp->pin_DataA(), lsig->pin(0));
656 connect(cmp->pin_DataB(), rsig->pin(0));
657 connect(cmp->pin_AEB(), osig->pin(0));
658 gate = cmp;
660 break;
662 case 'n': // !=
664 /* Handle the special case of single bit compare with a
665 single XOR gate. This is easy and direct. */
666 if (dwidth == 1) {
667 gate = new NetLogic(scope, scope->local_symbol(),
668 3, NetLogic::XOR, 1);
669 connect(gate->pin(0), osig->pin(0));
670 connect(gate->pin(1), lsig->pin(0));
671 connect(gate->pin(2), rsig->pin(0));
672 break;
675 /* Oh well, do the general case with a NetCompare. */
676 { NetCompare*cmp = new NetCompare(scope, scope->local_symbol(),
677 dwidth);
678 connect(cmp->pin_DataA(), lsig->pin(0));
679 connect(cmp->pin_DataB(), rsig->pin(0));
680 connect(cmp->pin_ANEB(), osig->pin(0));
681 gate = cmp;
683 break;
685 default:
686 assert(0);
689 gate->rise_time(rise);
690 gate->fall_time(fall);
691 gate->decay_time(decay);
692 des->add_node(gate);
694 return osig;
698 * Elaborate a divider gate. This function create a NetDivide gate
699 * which has exactly the right sized DataA, DataB and Result ports. If
700 * the l-value is wider then the result, then pad.
702 NetNet* PEBinary::elaborate_net_div_(Design*des, NetScope*scope,
703 unsigned lwidth,
704 const NetExpr* rise,
705 const NetExpr* fall,
706 const NetExpr* decay) const
708 NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0);
709 if (lsig == 0) return 0;
710 NetNet*rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
711 if (rsig == 0) return 0;
714 // Check the l-value width. If it is unspecified, then use the
715 // largest operand width as the l-value width. Restrict the
716 // result width to the width of the largest operand, because
717 // there is no value is excess divider.
719 unsigned rwidth = lwidth;
721 if (rwidth == 0) {
722 rwidth = lsig->vector_width();
723 if (rsig->vector_width() > rwidth)
724 rwidth = rsig->vector_width();
726 lwidth = rwidth;
729 if ((rwidth > lsig->vector_width()) && (rwidth > rsig->vector_width())) {
730 rwidth = lsig->vector_width();
731 if (rsig->vector_width() > rwidth)
732 rwidth = rsig->vector_width();
735 /* The arguments of a divide must have the same type. */
736 if (lsig->data_type() != rsig->data_type()) {
737 cerr << get_line() << ": error: Arguments of divide "
738 << "have different data types." << endl;
739 cerr << get_line() << ": : Left argument is "
740 << lsig->data_type() << ", right argument is "
741 << rsig->data_type() << "." << endl;
742 des->errors += 1;
745 ivl_variable_type_t data_type = lsig->data_type();
747 // Create a device with the calculated dimensions.
748 NetDivide*div = new NetDivide(scope, scope->local_symbol(), rwidth,
749 lsig->vector_width(),
750 rsig->vector_width());
751 des->add_node(div);
753 div->set_signed(lsig->get_signed() && rsig->get_signed());
755 // Connect the left and right inputs of the divider to the
756 // nets that are the left and right expressions.
758 connect(div->pin_DataA(), lsig->pin(0));
759 connect(div->pin_DataB(), rsig->pin(0));
762 // Make an output signal that is the width of the l-value.
763 // Due to above calculation of rwidth, we know that the result
764 // will be no more than the l-value, so it is safe to connect
765 // all the result pins to the osig.
767 NetNet*osig = new NetNet(scope, scope->local_symbol(),
768 NetNet::IMPLICIT, lwidth);
769 osig->local_flag(true);
770 osig->data_type(data_type);
771 osig->set_signed(div->get_signed());
773 connect(div->pin_Result(), osig->pin(0));
776 return osig;
780 * Elaborate a modulo gate.
782 NetNet* PEBinary::elaborate_net_mod_(Design*des, NetScope*scope,
783 unsigned lwidth,
784 const NetExpr* rise,
785 const NetExpr* fall,
786 const NetExpr* decay) const
788 NetNet*lsig = left_->elaborate_net(des, scope, 0, 0, 0, 0);
789 if (lsig == 0) return 0;
790 NetNet*rsig = right_->elaborate_net(des, scope, 0, 0, 0, 0);
791 if (rsig == 0) return 0;
793 /* The arguments of a modulus must have the same type. */
794 if (lsig->data_type() != rsig->data_type()) {
795 cerr << get_line() << ": error: Arguments of modulus "
796 << "have different data types." << endl;
797 cerr << get_line() << ": : Left argument is "
798 << lsig->data_type() << ", right argument is "
799 << rsig->data_type() << "." << endl;
800 des->errors += 1;
803 ivl_variable_type_t data_type = lsig->data_type();
805 /* rwidth is result width. */
806 unsigned rwidth = lwidth;
807 if (rwidth == 0) {
808 rwidth = lsig->vector_width();
809 if (rsig->vector_width() > rwidth)
810 rwidth = rsig->vector_width();
812 lwidth = rwidth;
815 NetModulo*mod = new NetModulo(scope, scope->local_symbol(), rwidth,
816 lsig->vector_width(),
817 rsig->vector_width());
818 mod->set_line(*this);
819 des->add_node(mod);
821 connect(mod->pin_DataA(), lsig->pin(0));
822 connect(mod->pin_DataB(), rsig->pin(0));
824 NetNet*osig = new NetNet(scope, scope->local_symbol(),
825 NetNet::IMPLICIT, rwidth);
826 osig->set_line(*this);
827 osig->data_type(data_type);
828 osig->local_flag(true);
830 connect(mod->pin_Result(), osig->pin(0));
832 return osig;
835 NetNet* PEBinary::elaborate_net_log_(Design*des, NetScope*scope,
836 unsigned lwidth,
837 const NetExpr* rise,
838 const NetExpr* fall,
839 const NetExpr* decay) const
841 NetNet*lsig = left_->elaborate_net(des, scope, 0, 0, 0, 0);
842 NetNet*rsig = right_->elaborate_net(des, scope, 0, 0, 0, 0);
843 if (lsig == 0) {
844 cerr << get_line() << ": error: Cannot elaborate ";
845 left_->dump(cerr);
846 cerr << endl;
847 return 0;
849 if (rsig == 0) {
850 cerr << get_line() << ": error: Cannot elaborate ";
851 right_->dump(cerr);
852 cerr << endl;
853 return 0;
856 NetLogic*gate;
857 switch (op_) {
858 case 'a':
859 gate = new NetLogic(scope, scope->local_symbol(),
860 3, NetLogic::AND, 1);
861 break;
862 case 'o':
863 gate = new NetLogic(scope, scope->local_symbol(),
864 3, NetLogic::OR, 1);
865 break;
866 default:
867 assert(0);
869 gate->rise_time(rise);
870 gate->fall_time(fall);
871 gate->decay_time(decay);
873 // The first OR gate returns 1 if the left value is true...
874 if (lsig->vector_width() > 1) {
875 NetUReduce*gate_tmp = new NetUReduce(scope, scope->local_symbol(),
876 NetUReduce::OR,
877 lsig->vector_width());
878 connect(gate_tmp->pin(1), lsig->pin(0));
879 connect(gate->pin(1), gate_tmp->pin(0));
881 /* The reduced logical value is a new nexus, create a
882 temporary signal to represent it. */
883 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
884 NetNet::IMPLICIT, 1);
885 tmp->data_type(IVL_VT_LOGIC);
886 tmp->local_flag(true);
887 connect(gate->pin(1), tmp->pin(0));
889 des->add_node(gate_tmp);
891 } else {
892 connect(gate->pin(1), lsig->pin(0));
895 // The second OR gate returns 1 if the right value is true...
896 if (rsig->vector_width() > 1) {
897 NetUReduce*gate_tmp = new NetUReduce(scope, scope->local_symbol(),
898 NetUReduce::OR,
899 rsig->vector_width());
900 connect(gate_tmp->pin(1), rsig->pin(0));
901 connect(gate->pin(2), gate_tmp->pin(0));
903 /* The reduced logical value is a new nexus, create a
904 temporary signal to represent it. */
905 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
906 NetNet::IMPLICIT, 1);
907 tmp->data_type(IVL_VT_LOGIC);
908 tmp->local_flag(true);
909 connect(gate->pin(2), tmp->pin(0));
911 des->add_node(gate_tmp);
913 } else {
914 connect(gate->pin(2), rsig->pin(0));
917 // The output is the AND/OR of the two logic values.
918 NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE);
919 osig->local_flag(true);
920 osig->data_type(IVL_VT_LOGIC);
921 connect(gate->pin(0), osig->pin(0));
922 des->add_node(gate);
923 return osig;
926 NetNet* PEBinary::elaborate_net_mul_(Design*des, NetScope*scope,
927 unsigned lwidth,
928 const NetExpr* rise,
929 const NetExpr* fall,
930 const NetExpr* decay) const
932 verinum*lnum = left_->eval_const(des, scope);
933 verinum*rnum = right_->eval_const(des, scope);
935 /* Detect and handle the special case that both the operands
936 of the multiply are constant expressions. Evaluate the
937 value and make this a simple constant. */
938 if (lnum && rnum) {
939 verinum prod = *lnum * *rnum;
940 if (lwidth == 0)
941 lwidth = prod.len();
943 verinum res (verinum::V0, lwidth);
944 for (unsigned idx = 0
945 ; idx < prod.len() && idx < lwidth
946 ; idx += 1) {
947 res.set(idx, prod.get(idx));
950 NetConst*odev = new NetConst(scope, scope->local_symbol(), res);
951 des->add_node(odev);
952 odev->set_line(*this);
954 NetNet*osig = new NetNet(scope, scope->local_symbol(),
955 NetNet::IMPLICIT, lwidth);
956 osig->set_line(*this);
957 osig->local_flag(true);
958 osig->data_type(IVL_VT_LOGIC);
960 connect(odev->pin(0), osig->pin(0));
962 return osig;
965 NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0);
966 if (lsig == 0) return 0;
967 NetNet*rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0);
968 if (rsig == 0) return 0;
970 // The mult is signed if both its operands are signed.
971 bool arith_is_signed = lsig->get_signed() && rsig->get_signed();
973 /* The arguments of a divide must have the same type. */
974 if (lsig->data_type() != rsig->data_type()) {
975 cerr << get_line() << ": error: Arguments of multiply "
976 << "have different data types." << endl;
977 cerr << get_line() << ": : Left argument is "
978 << lsig->data_type() << ", right argument is "
979 << rsig->data_type() << "." << endl;
980 des->errors += 1;
983 ivl_variable_type_t data_type = lsig->data_type();
985 unsigned rwidth = lwidth;
986 if (rwidth == 0) {
987 rwidth = lsig->vector_width() + rsig->vector_width();
988 lwidth = rwidth;
991 if (arith_is_signed) {
992 lsig = pad_to_width_signed(des, lsig, rwidth);
993 rsig = pad_to_width_signed(des, rsig, rwidth);
996 NetMult*mult = new NetMult(scope, scope->local_symbol(), rwidth,
997 lsig->vector_width(),
998 rsig->vector_width());
999 mult->set_line(*this);
1000 des->add_node(mult);
1002 mult->set_signed( arith_is_signed );
1004 connect(mult->pin_DataA(), lsig->pin(0));
1005 connect(mult->pin_DataB(), rsig->pin(0));
1007 // Make a signal to carry the output from the multiply.
1008 NetNet*osig = new NetNet(scope, scope->local_symbol(),
1009 NetNet::IMPLICIT, rwidth);
1010 osig->data_type(data_type);
1011 osig->local_flag(true);
1012 connect(mult->pin_Result(), osig->pin(0));
1014 return osig;
1017 NetNet* PEBinary::elaborate_net_shift_(Design*des, NetScope*scope,
1018 unsigned lwidth,
1019 const NetExpr* rise,
1020 const NetExpr* fall,
1021 const NetExpr* decay) const
1023 NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0);
1024 if (lsig == 0) return 0;
1026 if (lsig->vector_width() > lwidth)
1027 lwidth = lsig->vector_width();
1029 bool right_flag = op_ == 'r' || op_ == 'R';
1030 bool signed_flag = op_ == 'R';
1031 ivl_variable_type_t data_type = lsig->data_type();
1033 /* Handle the special case of a constant shift amount. There
1034 is no reason in this case to create a gate at all, just
1035 connect the lsig to the osig with the bit positions
1036 shifted. Use a NetPartSelect to select the parts of the
1037 left expression that survive the shift, and a NetConcat to
1038 concatenate a constant for padding. */
1039 if (verinum*rval = right_->eval_const(des, scope)) {
1040 assert(rval->is_defined());
1041 unsigned dist = rval->as_ulong();
1043 /* Very special case: constant 0 shift. Simply return
1044 the left signal again. */
1045 if (dist == 0) return lsig;
1047 /* Another very special case: constant shift the entire
1048 value away. The result is a const. */
1049 if (dist > lwidth) {
1050 assert(0);
1053 /* The construction that I'm making will ultimately
1054 connect its output to the osig here. This will be the
1055 result that I return from this function. */
1056 NetNet*osig = new NetNet(scope, scope->local_symbol(),
1057 NetNet::WIRE, lwidth);
1058 osig->data_type( data_type );
1059 osig->local_flag(true);
1062 /* Make the constant zero's that I'm going to pad to the
1063 top or bottom of the left expression. Attach a signal
1064 to its output so that I don't have to worry about it
1065 later. If the left expression is less then the
1066 desired width (and we are doing right shifts) then we
1067 can combine the expression padding with the distance
1068 padding to reduce nodes. */
1069 unsigned pad_width = dist;
1070 unsigned part_width = lwidth - dist;
1071 if (op_ == 'r' || op_ == 'R') {
1072 if (lsig->vector_width() < lwidth) {
1073 pad_width += lwidth - lsig->vector_width();
1074 part_width -= lwidth - lsig->vector_width();
1076 } else {
1078 /* The left net must be the same width as the
1079 result. The part select that I'm about to make relies
1080 on that. */
1081 lsig = pad_to_width(des, lsig, lwidth);
1085 NetNet*zero = new NetNet(scope, scope->local_symbol(),
1086 NetNet::WIRE, pad_width);
1087 zero->data_type( data_type );
1088 zero->local_flag(true);
1089 zero->set_line(*this);
1091 if (op_ == 'R') {
1092 NetPartSelect*sign_bit
1093 = new NetPartSelect(lsig, lsig->vector_width()-1,
1094 1, NetPartSelect::VP);
1095 des->add_node(sign_bit);
1096 NetReplicate*sign_pad
1097 = new NetReplicate(scope, scope->local_symbol(),
1098 pad_width, pad_width);
1099 des->add_node(sign_pad);
1100 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
1101 NetNet::WIRE, 1);
1102 tmp->data_type( data_type );
1103 tmp->local_flag(true);
1104 tmp->set_line(*this);
1105 connect(sign_bit->pin(0), tmp->pin(0));
1106 connect(sign_bit->pin(0), sign_pad->pin(1));
1108 connect(zero->pin(0), sign_pad->pin(0));
1110 } else {
1111 NetConst*zero_c = new NetConst(scope, scope->local_symbol(),
1112 verinum(verinum::V0, pad_width));
1113 des->add_node(zero_c);
1114 connect(zero->pin(0), zero_c->pin(0));
1117 /* Make a concatenation operator that will join the
1118 part-selected right expression at the pad values. */
1119 NetConcat*cc = new NetConcat(scope, scope->local_symbol(),
1120 lwidth, 2);
1121 cc->set_line(*this);
1122 des->add_node(cc);
1123 connect(cc->pin(0), osig->pin(0));
1125 /* Make the part select of the left expression and
1126 connect it to the lsb or msb of the concatenation,
1127 depending on the direction of the shift. */
1128 NetPartSelect*part;
1130 switch (op_) {
1131 case 'l': // Left shift === {lsig, zero}
1132 part = new NetPartSelect(lsig, 0, part_width,
1133 NetPartSelect::VP);
1134 connect(cc->pin(1), zero->pin(0));
1135 connect(cc->pin(2), part->pin(0));
1136 break;
1137 case 'R':
1138 case 'r': // right-shift === {zero, lsig}
1139 part = new NetPartSelect(lsig, dist, part_width,
1140 NetPartSelect::VP);
1141 connect(cc->pin(1), part->pin(0));
1142 connect(cc->pin(2), zero->pin(0));
1143 break;
1144 default:
1145 assert(0);
1148 des->add_node(part);
1150 if (debug_elaborate) {
1151 cerr << get_line() << ": debug: Elaborate shift "
1152 << "(" << op_ << ") as concatenation of "
1153 << pad_width << " zeros with " << part_width
1154 << " bits of expression." << endl;
1157 /* Attach a signal to the part select output (NetConcat
1158 input) */
1159 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
1160 NetNet::WIRE, part_width);
1161 tmp->data_type( data_type );
1162 tmp->local_flag(true);
1163 tmp->set_line(*this);
1164 connect(part->pin(0), tmp->pin(0));
1166 return osig;
1169 // Calculate the number of useful bits for the shift amount,
1170 // and elaborate the right_ expression as the shift amount.
1171 unsigned dwid = 0;
1172 while ((1U << dwid) < lwidth)
1173 dwid += 1;
1175 NetNet*rsig = right_->elaborate_net(des, scope, dwid, 0, 0, 0);
1176 if (rsig == 0) return 0;
1178 // Make the shift device itself, and the output
1179 // NetNet. Connect the Result output pins to the osig signal
1180 NetCLShift*gate = new NetCLShift(scope, scope->local_symbol(),
1181 lwidth, rsig->vector_width(),
1182 right_flag, signed_flag);
1183 des->add_node(gate);
1185 NetNet*osig = new NetNet(scope, scope->local_symbol(),
1186 NetNet::WIRE, lwidth);
1187 osig->data_type( data_type );
1188 osig->local_flag(true);
1189 osig->set_signed(signed_flag);
1191 connect(osig->pin(0), gate->pin_Result());
1193 // Connect the lsig (the left expression) to the Data input,
1194 // and pad it if necessary. The lwidth is the width of the
1195 // NetCLShift gate, and the D input must match.
1196 if (lsig->vector_width() < lwidth)
1197 lsig = pad_to_width(des, lsig, lwidth);
1199 assert(lsig->vector_width() <= lwidth);
1200 connect(lsig->pin(0), gate->pin_Data());
1202 // Connect the rsig (the shift amount expression) to the
1203 // Distance input.
1204 connect(rsig->pin(0), gate->pin_Distance());
1206 if (debug_elaborate) {
1207 cerr << get_line() << ": debug: "
1208 << "Elaborate LPM_SHIFT: width="<<gate->width()
1209 << ", swidth="<< gate->width_dist() << endl;
1212 return osig;
1216 * This method elaborates a call to a function in the context of a
1217 * continuous assignment. The definition of the function contains a
1218 * list of the ports, and an output port. The NetEUFunc that I create
1219 * here has a port for all the input ports and the output port. The
1220 * ports are connected by pins.
1222 NetNet* PECallFunction::elaborate_net(Design*des, NetScope*scope,
1223 unsigned width,
1224 const NetExpr* rise,
1225 const NetExpr* fall,
1226 const NetExpr* decay,
1227 Link::strength_t drive0,
1228 Link::strength_t drive1) const
1230 unsigned errors = 0;
1231 unsigned func_pins = 0;
1233 if (path_.front().name[0] == '$')
1234 return elaborate_net_sfunc_(des, scope,
1235 width, rise, fall, decay,
1236 drive0, drive1);
1239 /* Look up the function definition. */
1240 NetFuncDef*def = des->find_function(scope, path_);
1241 if (def == 0) {
1242 cerr << get_line() << ": error: No function " << path_ <<
1243 " in this context (" << scope_path(scope) << ")." << endl;
1244 des->errors += 1;
1245 return 0;
1247 assert(def);
1249 NetScope*dscope = def->scope();
1250 assert(dscope);
1252 /* This must be a ufuction that returns a signal. */
1253 assert(def->return_sig());
1255 /* check the validity of the parameters. */
1256 if (! check_call_matches_definition_(des, dscope))
1257 return 0;
1259 /* Elaborate all the parameters of the function call,
1260 and collect the resulting NetNet objects. All the
1261 parameters take on the size of the target port. */
1263 svector<NetNet*> eparms (def->port_count());
1264 for (unsigned idx = 0 ; idx < eparms.count() ; idx += 1) {
1265 const NetNet* port_reg = def->port(idx);
1266 NetNet*tmp = parms_[idx]->elaborate_net(des, scope,
1267 port_reg->vector_width(),
1268 0, 0, 0,
1269 Link::STRONG,
1270 Link::STRONG);
1271 if (tmp == 0) {
1272 cerr << get_line() << ": error: Unable to elaborate "
1273 << "port " << idx << " of call to " << path_ <<
1274 "." << endl;
1275 errors += 1;
1276 continue;
1279 func_pins += tmp->pin_count();
1280 eparms[idx] = tmp;
1283 if (errors > 0)
1284 return 0;
1287 NetUserFunc*net = new NetUserFunc(scope,
1288 scope->local_symbol(),
1289 dscope);
1290 des->add_node(net);
1292 /* Create an output signal and connect it to the output pins
1293 of the function net. */
1294 NetNet*osig = new NetNet(scope, scope->local_symbol(),
1295 NetNet::WIRE,
1296 def->return_sig()->vector_width());
1297 osig->local_flag(true);
1298 osig->data_type(def->return_sig()->data_type());
1300 connect(net->pin(0), osig->pin(0));
1302 /* Connect the parameter pins to the parameter expressions. */
1303 for (unsigned idx = 0 ; idx < eparms.count() ; idx += 1) {
1304 const NetNet* port = def->port(idx);
1305 NetNet*cur = eparms[idx];
1307 NetNet*tmp = pad_to_width(des, cur, port->vector_width());
1309 connect(net->pin(idx+1), tmp->pin(0));
1312 return osig;
1315 NetNet* PECallFunction::elaborate_net_sfunc_(Design*des, NetScope*scope,
1316 unsigned width,
1317 const NetExpr* rise,
1318 const NetExpr* fall,
1319 const NetExpr* decay,
1320 Link::strength_t drive0,
1321 Link::strength_t drive1) const
1323 perm_string name = peek_tail_name(path_);
1325 /* Handle the special case that the function call is to
1326 $signed. This takes a single expression argument, and
1327 forces it to be a signed result. Otherwise, it is as if the
1328 $signed did not exist. */
1329 if (strcmp(name, "$signed") == 0) {
1330 if ((parms_.count() != 1) || (parms_[0] == 0)) {
1331 cerr << get_line() << ": error: The $signed() function "
1332 << "takes exactly one(1) argument." << endl;
1333 des->errors += 1;
1334 return 0;
1337 PExpr*expr = parms_[0];
1338 NetNet*sub = expr->elaborate_net(des, scope, width, rise,
1339 fall, decay, drive0, drive1);
1340 sub->set_signed(true);
1341 return sub;
1344 /* handle $unsigned like $signed */
1345 if (strcmp(name, "$unsigned") == 0) {
1346 if ((parms_.count() != 1) || (parms_[0] == 0)) {
1347 cerr << get_line() << ": error: The $unsigned() function "
1348 << "takes exactly one(1) argument." << endl;
1349 des->errors += 1;
1350 return 0;
1353 PExpr*expr = parms_[0];
1354 NetNet*sub = expr->elaborate_net(des, scope, width, rise,
1355 fall, decay, drive0, drive1);
1356 sub->set_signed(false);
1357 return sub;
1360 const struct sfunc_return_type*def = lookup_sys_func(name);
1362 if (def == 0) {
1363 cerr << get_line() << ": error: System function "
1364 << peek_tail_name(path_) << " not defined." << endl;
1365 des->errors += 1;
1366 return 0;
1369 NetSysFunc*net = new NetSysFunc(scope, scope->local_symbol(),
1370 def, 1+parms_.count());
1371 des->add_node(net);
1372 net->set_line(*this);
1374 NetNet*osig = new NetNet(scope, scope->local_symbol(),
1375 NetNet::WIRE, def->wid);
1376 osig->local_flag(true);
1377 osig->data_type(def->type);
1378 osig->set_line(*this);
1380 connect(net->pin(0), osig->pin(0));
1382 for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
1383 NetNet*tmp = parms_[idx]->elaborate_net(des, scope, 0,
1384 0, 0, 0,
1385 Link::STRONG, Link::STRONG);
1386 if (tmp == 0) {
1387 cerr << get_line() << ": error: Unable to elaborate "
1388 << "port " << idx << " of call to " << path_ <<
1389 "." << endl;
1390 continue;
1393 connect(net->pin(1+idx), tmp->pin(0));
1395 return osig;
1400 * The concatenation operator, as a net, is a wide signal that is
1401 * connected to all the pins of the elaborated expression nets.
1403 NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope,
1404 unsigned,
1405 const NetExpr* rise,
1406 const NetExpr* fall,
1407 const NetExpr* decay,
1408 Link::strength_t drive0,
1409 Link::strength_t drive1) const
1411 svector<NetNet*>nets (parms_.count());
1412 unsigned vector_width = 0;
1413 unsigned errors = 0;
1414 unsigned repeat = 1;
1416 /* The repeat expression must evaluate to a compile-time
1417 constant. This is used to generate the width of the
1418 concatenation. */
1419 if (repeat_) {
1420 NetExpr*etmp = elab_and_eval(des, scope, repeat_, -1);
1421 assert(etmp);
1422 NetEConst*erep = dynamic_cast<NetEConst*>(etmp);
1424 if (erep == 0) {
1425 cerr << get_line() << ": error: Unable to "
1426 << "evaluate constant repeat expression." << endl;
1427 des->errors += 1;
1428 return 0;
1431 repeat = erep->value().as_ulong();
1432 delete etmp;
1434 if (repeat == 0) {
1435 cerr << get_line() << ": error: Concatenation epeat "
1436 "may not be 0."
1437 << endl;
1438 des->errors += 1;
1439 return 0;
1443 if (debug_elaborate) {
1444 cerr << get_line() <<": debug: PEConcat concat repeat="
1445 << repeat << "." << endl;
1448 /* The operands of the concatenation must contain all
1449 self-determined arguments. Set this flag to force an error
1450 message if this is not the case. */
1451 const bool save_flag = must_be_self_determined_flag;
1452 must_be_self_determined_flag = true;
1454 /* Elaborate the operands of the concatenation. */
1455 for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
1457 if (parms_[idx] == 0) {
1458 cerr << get_line() << ": error: Empty expressions "
1459 << "not allowed in concatenations." << endl;
1460 errors += 1;
1461 continue;
1464 /* Look for the special case of an unsized number in a
1465 concatenation expression. Mark this as an error, but
1466 allow elaboration to continue to see if I can find
1467 more errors. */
1469 if (PENumber*tmp = dynamic_cast<PENumber*>(parms_[idx])) {
1470 if (tmp->value().has_len() == false) {
1471 cerr << get_line() << ": error: Number "
1472 << tmp->value() << " with indefinite size"
1473 << " in concatenation." << endl;
1474 errors += 1;
1478 nets[idx] = parms_[idx]->elaborate_net(des, scope, 0,
1479 rise,fall,decay);
1480 if (nets[idx] == 0)
1481 errors += 1;
1482 else
1483 vector_width += nets[idx]->vector_width();
1486 must_be_self_determined_flag = save_flag;
1488 /* If any of the sub expressions failed to elaborate, then
1489 delete all those that did and abort myself. */
1490 if (errors) {
1491 for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
1492 if (nets[idx]) delete nets[idx];
1494 des->errors += 1;
1495 return 0;
1498 if (debug_elaborate) {
1499 cerr << get_line() <<": debug: PEConcat concat collected "
1500 << "width=" << vector_width << ", repeat=" << repeat
1501 << " of " << nets.count() << " expressions." << endl;
1504 NetConcat*dev = new NetConcat(scope, scope->local_symbol(),
1505 vector_width*repeat,
1506 nets.count()*repeat);
1507 dev->set_line(*this);
1508 des->add_node(dev);
1510 /* Make the temporary signal that connects to all the
1511 operands, and connect it up. Scan the operands of the
1512 concat operator from least significant to most significant,
1513 which is opposite from how they are given in the list.
1515 Allow for a repeat count other than 1 by repeating the
1516 connect loop as many times as necessary. */
1518 NetNet*osig = new NetNet(scope, scope->local_symbol(),
1519 NetNet::IMPLICIT, vector_width * repeat);
1520 osig->data_type(IVL_VT_LOGIC);
1522 connect(dev->pin(0), osig->pin(0));
1524 unsigned cur_pin = 1;
1525 for (unsigned rpt = 0; rpt < repeat ; rpt += 1) {
1526 for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
1527 NetNet*cur = nets[nets.count()-idx-1];
1528 connect(dev->pin(cur_pin++), cur->pin(0));
1533 osig->local_flag(true);
1534 return osig;
1538 * This private method handles the special case that we have a
1539 * non-constant bit-select of an identifier. We already know that the
1540 * signal that is represented is "sig".
1542 NetNet* PEIdent::elaborate_net_bitmux_(Design*des, NetScope*scope,
1543 NetNet*sig,
1544 const NetExpr* rise,
1545 const NetExpr* fall,
1546 const NetExpr* decay,
1547 Link::strength_t drive0,
1548 Link::strength_t drive1) const
1550 const name_component_t&name_tail = path_.back();
1551 ivl_assert(*this, !name_tail.index.empty());
1553 const index_component_t&index_tail = name_tail.index.back();
1554 ivl_assert(*this, index_tail.sel == index_component_t::SEL_BIT);
1555 ivl_assert(*this, index_tail.msb != 0);
1556 ivl_assert(*this, index_tail.lsb == 0);
1558 /* Elaborate the selector. */
1559 NetNet*sel;
1561 if (sig->msb() < sig->lsb()) {
1562 NetExpr*sel_expr = index_tail.msb->elaborate_expr(des, scope, -1, false);
1563 sel_expr = make_sub_expr(sig->lsb(), sel_expr);
1564 if (NetExpr*tmp = sel_expr->eval_tree()) {
1565 delete sel_expr;
1566 sel_expr = tmp;
1569 sel = sel_expr->synthesize(des);
1571 } else if (sig->lsb() != 0) {
1572 NetExpr*sel_expr = index_tail.msb->elaborate_expr(des, scope, -1,false);
1573 sel_expr = make_add_expr(sel_expr, - sig->lsb());
1574 if (NetExpr*tmp = sel_expr->eval_tree()) {
1575 delete sel_expr;
1576 sel_expr = tmp;
1579 sel = sel_expr->synthesize(des);
1581 } else {
1582 sel = index_tail.msb->elaborate_net(des, scope, 0, 0, 0, 0);
1585 if (debug_elaborate) {
1586 cerr << get_line() << ": debug: Create NetPartSelect "
1587 << "using signal " << sel->name() << " as selector"
1588 << endl;
1591 /* Create a part select that takes a non-constant offset and a
1592 width of 1. */
1593 NetPartSelect*mux = new NetPartSelect(sig, sel, 1);
1594 des->add_node(mux);
1595 mux->set_line(*this);
1597 NetNet*out = new NetNet(scope, scope->local_symbol(),
1598 NetNet::WIRE, 1);
1599 out->data_type(sig->data_type());
1601 connect(out->pin(0), mux->pin(0));
1602 return out;
1605 NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope,
1606 unsigned lwidth,
1607 const NetExpr* rise,
1608 const NetExpr* fall,
1609 const NetExpr* decay,
1610 Link::strength_t drive0,
1611 Link::strength_t drive1) const
1613 ivl_assert(*this, scope);
1615 const name_component_t&name_tail = path_.back();
1617 NetNet* sig = 0;
1618 const NetExpr*par = 0;
1619 NetEvent* eve = 0;
1621 symbol_search(des, scope, path_, sig, par, eve);
1623 /* If this is a parameter name, then create a constant node
1624 that connects to a signal with the correct name. */
1625 if (par != 0) {
1627 const NetEConst*pc = dynamic_cast<const NetEConst*>(par);
1628 assert(pc);
1629 verinum pvalue = pc->value();
1631 /* If the desired lwidth is more than the width of the
1632 constant value, extend the value to fit the desired
1633 output. */
1634 if (lwidth > pvalue.len()) {
1635 verinum tmp ((uint64_t)0, lwidth);
1636 for (unsigned idx = 0 ; idx < pvalue.len() ; idx += 1)
1637 tmp.set(idx, pvalue.get(idx));
1639 pvalue = tmp;
1642 sig = new NetNet(scope, scope->local_symbol(),
1643 NetNet::IMPLICIT, pvalue.len());
1644 sig->set_line(*this);
1645 sig->data_type(IVL_VT_LOGIC);
1646 NetConst*cp = new NetConst(scope, scope->local_symbol(),
1647 pvalue);
1648 cp->set_line(*this);
1649 des->add_node(cp);
1650 for (unsigned idx = 0; idx < sig->pin_count(); idx += 1)
1651 connect(sig->pin(idx), cp->pin(idx));
1654 /* Check for the error case that the name is not found, and it
1655 is hierarchical. We can't just create a name in another
1656 scope, it's just not allowed. */
1657 if (sig == 0 && path_.size() != 1) {
1658 cerr << get_line() << ": error: The hierarchical name "
1659 << path_ << " is undefined in "
1660 << scope_path(scope) << "." << endl;
1662 pform_name_t tmp_path = path_;
1663 tmp_path.pop_back();
1665 list<hname_t> stmp_path = eval_scope_path(des, scope, tmp_path);
1666 NetScope*tmp_scope = des->find_scope(scope, stmp_path);
1667 if (tmp_scope == 0) {
1668 cerr << get_line() << ": : I can't even find "
1669 << "the scope " << tmp_path << "." << endl;
1672 des->errors += 1;
1673 return 0;
1676 /* Fallback, this may be an implicitly declared net. */
1677 if (sig == 0) {
1678 NetNet::Type nettype = scope->default_nettype();
1679 sig = new NetNet(scope, name_tail.name,
1680 nettype, 1);
1681 sig->data_type(IVL_VT_LOGIC);
1683 if (error_implicit || (nettype == NetNet::NONE)) {
1684 cerr << get_line() << ": error: "
1685 << scope_path(scope) << "." << name_tail.name
1686 << " not defined in this scope." << endl;
1687 des->errors += 1;
1689 } else if (warn_implicit) {
1690 cerr << get_line() << ": warning: implicit "
1691 "definition of wire " << scope_path(scope)
1692 << "." << name_tail.name << "." << endl;
1696 ivl_assert(*this, sig);
1698 /* Handle the case that this is an array elsewhere. */
1699 if (sig->array_dimensions() > 0) {
1700 if (name_tail.index.size() == 0) {
1701 cerr << get_line() << ": error: Array " << sig->name()
1702 << " cannot be used here without an index." << endl;
1703 des->errors += 1;
1704 return 0;
1707 return elaborate_net_array_(des, scope, sig, lwidth,
1708 rise, fall, decay,
1709 drive0, drive1);
1712 return elaborate_net_net_(des, scope, sig, lwidth,
1713 rise, fall, decay, drive0, drive1);
1717 NetNet* PEIdent::process_select_(Design*des, NetScope*scope,
1718 NetNet*sig) const
1721 // If there are more index items then there are array
1722 // dimensions, then treat them as word part selects. For
1723 // example, if this is a memory array, then array dimensions
1724 // is the first and part select the remainder.
1725 unsigned midx, lidx;
1726 if (! eval_part_select_(des, scope, sig, midx, lidx))
1727 return sig;
1729 unsigned part_count = midx-lidx+1;
1731 // Maybe this is a full-width constant part select? If
1732 // so, do nothing.
1733 if (part_count == sig->vector_width())
1734 return sig;
1736 if (debug_elaborate) {
1737 cerr << get_line() << ": debug: Elaborate part select"
1738 << " of word from " << sig->name() << "[base="<<lidx
1739 << " wid=" << part_count << "]" << endl;
1742 NetPartSelect*ps = new NetPartSelect(sig, lidx, part_count,
1743 NetPartSelect::VP);
1744 ps->set_line(*sig);
1745 des->add_node(ps);
1747 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
1748 NetNet::WIRE, part_count-1, 0);
1749 tmp->data_type( sig->data_type() );
1750 tmp->local_flag(true);
1751 connect(tmp->pin(0), ps->pin(0));
1753 return tmp;
1756 NetNet* PEIdent::elaborate_net_net_(Design*des, NetScope*scope,
1757 NetNet*sig, unsigned lwidth,
1758 const NetExpr* rise,
1759 const NetExpr* fall,
1760 const NetExpr* decay,
1761 Link::strength_t drive0,
1762 Link::strength_t drive1) const
1764 const name_component_t&name_tail = path_.back();
1766 index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
1767 if (!name_tail.index.empty())
1768 use_sel = name_tail.index.back().sel;
1770 switch (use_sel) {
1771 case index_component_t::SEL_IDX_UP:
1772 case index_component_t::SEL_IDX_DO:
1773 return elaborate_net_net_idx_up_(des, scope, sig, lwidth,
1774 rise, fall, decay, drive0, drive1);
1776 default:
1777 break;
1780 /* Catch the case of a non-constant bit select. That should be
1781 handled elsewhere. */
1782 if (use_sel == index_component_t::SEL_BIT) {
1783 const index_component_t&index_tail = name_tail.index.back();
1785 verinum*mval = index_tail.msb->eval_const(des, scope);
1786 if (mval == 0) {
1787 return elaborate_net_bitmux_(des, scope, sig, rise,
1788 fall, decay, drive0, drive1);
1791 delete mval;
1794 unsigned midx, lidx;
1795 if (! eval_part_select_(des, scope, sig, midx, lidx))
1796 return 0;
1798 unsigned part_count = midx-lidx+1;
1800 if (part_count != sig->vector_width()) {
1801 if (debug_elaborate) {
1802 cerr << get_line() << ": debug: Elaborate part select "
1803 << sig->name() << "[base="<<lidx
1804 << " wid=" << part_count << "]" << endl;
1807 NetPartSelect*ps = new NetPartSelect(sig, lidx, part_count,
1808 NetPartSelect::VP);
1809 ps->set_line(*sig);
1810 des->add_node(ps);
1812 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
1813 NetNet::WIRE, part_count-1, 0);
1814 tmp->data_type( sig->data_type() );
1815 tmp->local_flag(true);
1816 connect(tmp->pin(0), ps->pin(0));
1818 sig = tmp;
1823 return sig;
1826 NetNet* PEIdent::elaborate_net_net_idx_up_(Design*des, NetScope*scope,
1827 NetNet*sig, unsigned lwidth,
1828 const NetExpr* rise,
1829 const NetExpr* fall,
1830 const NetExpr* decay,
1831 Link::strength_t drive0,
1832 Link::strength_t drive1) const
1834 const name_component_t&name_tail = path_.back();
1835 ivl_assert(*this, !name_tail.index.empty());
1837 const index_component_t&index_tail = name_tail.index.back();
1838 ivl_assert(*this, index_tail.lsb != 0);
1839 ivl_assert(*this, index_tail.msb != 0);
1841 NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1);
1843 unsigned long wid = 0;
1844 calculate_up_do_width_(des, scope, wid);
1846 bool down_flag = name_tail.index.back().sel==index_component_t::SEL_IDX_DO;
1848 // Handle the special case that the base is constant as
1849 // well. In this case it can be converted to a conventional
1850 // part select.
1851 if (NetEConst*base_c = dynamic_cast<NetEConst*> (base)) {
1852 long lsv = base_c->value().as_long();
1854 // convert from -: to +: form.
1855 if (down_flag) lsv -= (wid-1);
1857 // If the part select convers exactly the entire
1858 // vector, then do not bother with it. Return the
1859 // signal itself.
1860 if (sig->sb_to_idx(lsv) == 0 && wid == sig->vector_width())
1861 return sig;
1863 NetPartSelect*sel = new NetPartSelect(sig, sig->sb_to_idx(lsv),
1864 wid, NetPartSelect::VP);
1865 sel->set_line(*this);
1866 des->add_node(sel);
1868 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
1869 NetNet::WIRE, wid);
1870 tmp->set_line(*this);
1871 tmp->data_type(sig->data_type());
1872 connect(tmp->pin(0), sel->pin(0));
1874 delete base;
1875 return tmp;
1878 if (sig->msb() > sig->lsb()) {
1879 long offset = sig->lsb();
1880 if (down_flag)
1881 offset += (wid-1);
1882 if (offset != 0)
1883 base = make_add_expr(base, 0-offset);
1884 } else {
1885 long vwid = sig->lsb() - sig->msb() + 1;
1886 long offset = sig->msb();
1887 if (down_flag)
1888 offset += (wid-1);
1889 base = make_sub_expr(vwid-offset-wid, base);
1892 NetPartSelect*sel = new NetPartSelect(sig, base->synthesize(des), wid);
1893 sel->set_line(*this);
1894 des->add_node(sel);
1896 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
1897 NetNet::WIRE, wid);
1898 tmp->set_line(*this);
1899 tmp->data_type(sig->data_type());
1900 connect(tmp->pin(0), sel->pin(0));
1902 delete base;
1903 return tmp;
1906 NetNet* PEIdent::elaborate_net_array_(Design*des, NetScope*scope,
1907 NetNet*sig, unsigned lwidth,
1908 const NetExpr* rise,
1909 const NetExpr* fall,
1910 const NetExpr* decay,
1911 Link::strength_t drive0,
1912 Link::strength_t drive1) const
1914 const name_component_t&name_tail = path_.back();
1915 ivl_assert(*this, name_tail.index.size() >= 1);
1916 const index_component_t&index_head = name_tail.index.front();
1917 ivl_assert(*this, index_head.sel == index_component_t::SEL_BIT);
1918 ivl_assert(*this, index_head.msb != 0);
1919 ivl_assert(*this, index_head.lsb == 0);
1921 if (debug_elaborate)
1922 cerr << get_line() << ": debug: elaborate array "
1923 << name_tail.name << " with index " << index_head << endl;
1925 NetExpr*index_ex = elab_and_eval(des, scope, index_head.msb, -1);
1926 if (index_ex == 0)
1927 return 0;
1929 if (NetEConst*index_co = dynamic_cast<NetEConst*> (index_ex)) {
1930 long index = index_co->value().as_long();
1932 if (!sig->array_index_is_valid(index)) {
1933 // Oops! The index is a constant known to be
1934 // outside the array. Change the expression to a
1935 // constant X vector.
1936 verinum xxx (verinum::Vx, sig->vector_width());
1937 NetConst*con_n = new NetConst(scope, scope->local_symbol(), xxx);
1938 des->add_node(con_n);
1939 con_n->set_line(*index_co);
1941 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
1942 NetNet::IMPLICIT, sig->vector_width());
1943 tmp->set_line(*this);
1944 tmp->local_flag(true);
1945 tmp->data_type(sig->data_type());
1946 connect(tmp->pin(0), con_n->pin(0));
1947 return tmp;
1950 assert(sig->array_index_is_valid(index));
1951 index = sig->array_index_to_address(index);
1953 if (debug_elaborate) {
1954 cerr << get_line() << ": debug: Elaborate word "
1955 << index << " of " << sig->name() << endl;
1958 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
1959 NetNet::IMPLICIT, sig->vector_width());
1960 tmp->set_line(*this);
1961 tmp->local_flag(true);
1962 tmp->data_type(sig->data_type());
1963 connect(tmp->pin(0), sig->pin(index));
1965 // If there are more indices then needed to get to the
1966 // word, then there is a part/bit select for the word.
1967 if (name_tail.index.size() > sig->array_dimensions())
1968 tmp = process_select_(des, scope, tmp);
1970 return tmp;
1973 unsigned selwid = index_ex->expr_width();
1975 NetArrayDq*mux = new NetArrayDq(scope, scope->local_symbol(),
1976 sig, selwid);
1977 mux->set_line(*this);
1978 des->add_node(mux);
1980 // Adjust the expression to calculate the canonical offset?
1981 if (long array_base = sig->array_first()) {
1982 index_ex = make_add_expr(index_ex, 0-array_base);
1985 NetNet*index_net = index_ex->synthesize(des);
1986 connect(mux->pin_Address(), index_net->pin(0));
1988 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
1989 NetNet::IMPLICIT, sig->vector_width());
1990 tmp->set_line(*this);
1991 tmp->local_flag(true);
1992 tmp->data_type(sig->data_type());
1993 connect(tmp->pin(0), mux->pin_Result());
1994 #if 0
1996 // If there are more index items then there are array
1997 // dimensions, then treat them as word part selects. For
1998 // example, if this is a memory array, then array dimensions
1999 // is 1 and
2000 unsigned midx, lidx;
2001 if (eval_part_select_(des, scope, sig, midx, lidx)) do {
2003 unsigned part_count = midx-lidx+1;
2005 // Maybe this is a full-width constant part select? If
2006 // so, do nothing.
2007 if (part_count == sig->vector_width())
2008 break;
2010 if (debug_elaborate) {
2011 cerr << get_line() << ": debug: Elaborate part select"
2012 << " of word from " << sig->name() << "[base="<<lidx
2013 << " wid=" << part_count << "]" << endl;
2016 NetPartSelect*ps = new NetPartSelect(sig, lidx, part_count,
2017 NetPartSelect::VP);
2018 ps->set_line(*sig);
2019 des->add_node(ps);
2021 NetNet*tmp2 = new NetNet(scope, scope->local_symbol(),
2022 NetNet::WIRE, part_count-1, 0);
2023 tmp2->data_type( tmp->data_type() );
2024 tmp2->local_flag(true);
2025 connect(tmp2->pin(0), ps->pin(0));
2027 tmp = tmp2;
2028 } while (0);
2029 #else
2030 if (name_tail.index.size() > sig->array_dimensions())
2031 tmp = process_select_(des, scope, sig);
2033 #endif
2034 return tmp;
2038 * The concatenation is also OK an an l-value. This method elaborates
2039 * it as a structural l-value. The return values is the *input* net of
2040 * the l-value, which may feed via part selects to the final
2041 * destination. The caller can connect gate outputs to this signal to
2042 * make the l-value connections.
2044 NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
2045 bool implicit_net_ok,
2046 bool bidirectional_flag) const
2048 assert(scope);
2050 svector<NetNet*>nets (parms_.count());
2051 unsigned width = 0;
2052 unsigned errors = 0;
2054 if (repeat_) {
2055 cerr << get_line() << ": sorry: I do not know how to"
2056 " elaborate repeat concatenation nets." << endl;
2057 return 0;
2060 /* Elaborate the operands of the concatenation. */
2061 for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
2063 if (debug_elaborate) {
2064 cerr << get_line() << ": debug: Elaborate subexpression "
2065 << idx << " of " << nets.count() << " l-values: "
2066 << *parms_[idx] << endl;
2069 if (parms_[idx] == 0) {
2070 cerr << get_line() << ": error: Empty expressions "
2071 << "not allowed in concatenations." << endl;
2072 errors += 1;
2073 continue;
2076 if (bidirectional_flag) {
2077 nets[idx] = parms_[idx]->elaborate_bi_net(des, scope);
2078 } else {
2079 nets[idx] = parms_[idx]->elaborate_lnet(des, scope,
2080 implicit_net_ok);
2082 if (nets[idx] == 0)
2083 errors += 1;
2084 else
2085 width += nets[idx]->vector_width();
2088 /* If any of the sub expressions failed to elaborate, then
2089 delete all those that did and abort myself. */
2090 if (errors) {
2091 for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
2092 if (nets[idx]) delete nets[idx];
2094 des->errors += 1;
2095 return 0;
2098 /* Make the temporary signal that connects to all the
2099 operands, and connect it up. Scan the operands of the
2100 concat operator from most significant to least significant,
2101 which is the order they are given in the concat list. */
2103 NetNet*osig = new NetNet(scope, scope->local_symbol(),
2104 NetNet::IMPLICIT, width);
2106 /* Assume that the data types of the nets are all the same, so
2107 we can take the data type of any, the first will do. */
2108 osig->data_type(nets[0]->data_type());
2109 osig->local_flag(true);
2110 osig->set_line(*this);
2112 if (debug_elaborate) {
2113 cerr << get_line() << ": debug: Generating part selects "
2114 << "to connect input l-value to subexpressions."
2115 << endl;
2118 NetPartSelect::dir_t part_dir = bidirectional_flag
2119 ? NetPartSelect::BI
2120 : NetPartSelect::VP;
2122 for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
2123 unsigned wid = nets[idx]->vector_width();
2124 unsigned off = width - wid;
2125 NetPartSelect*ps = new NetPartSelect(osig, off, wid, part_dir);
2126 des->add_node(ps);
2128 connect(ps->pin(1), osig->pin(0));
2129 connect(ps->pin(0), nets[idx]->pin(0));
2131 assert(wid <= width);
2132 width -= wid;
2134 assert(width == 0);
2136 osig->data_type(nets[0]->data_type());
2137 osig->local_flag(true);
2138 return osig;
2141 NetNet* PEConcat::elaborate_lnet(Design*des, NetScope*scope,
2142 bool implicit_net_ok) const
2144 return elaborate_lnet_common_(des, scope, implicit_net_ok, false);
2147 NetNet* PEConcat::elaborate_bi_net(Design*des, NetScope*scope) const
2149 return elaborate_lnet_common_(des, scope, true, true);
2153 * Elaborate a number as a NetConst object.
2155 NetNet* PEFNumber::elaborate_net(Design*des, NetScope*scope,
2156 unsigned lwidth,
2157 const NetExpr* rise,
2158 const NetExpr* fall,
2159 const NetExpr* decay,
2160 Link::strength_t drive0,
2161 Link::strength_t drive1) const
2163 if (debug_elaborate) {
2164 cerr << get_line() << ": debug: Elaborate real literal node, "
2165 << "value=" << value() << "." << endl;
2168 NetLiteral*obj = new NetLiteral(scope, scope->local_symbol(), value());
2169 obj->set_line(*this);
2170 des->add_node(obj);
2172 NetNet*net = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, 1);
2173 net->data_type(IVL_VT_REAL);
2174 net->local_flag(true);
2176 connect(net->pin(0), obj->pin(0));
2177 return net;
2181 * A private method to create an implicit net.
2183 NetNet* PEIdent::make_implicit_net_(Design*des, NetScope*scope) const
2185 NetNet::Type nettype = scope->default_nettype();
2186 NetNet*sig = 0;
2188 if (!error_implicit && nettype!=NetNet::NONE) {
2189 sig = new NetNet(scope, peek_tail_name(path_),
2190 NetNet::IMPLICIT, 1);
2191 /* Implicit nets are always scalar logic. */
2192 sig->data_type(IVL_VT_LOGIC);
2194 if (warn_implicit) {
2195 cerr << get_line() << ": warning: implicit "
2196 "definition of wire logic " << scope_path(scope)
2197 << "." << peek_tail_name(path_) << "." << endl;
2200 } else {
2201 cerr << get_line() << ": error: Net " << path_
2202 << " is not defined in this context." << endl;
2203 des->errors += 1;
2204 return 0;
2207 return sig;
2211 * This private method evaluates the part selects (if any) for the
2212 * signal. The sig argument is the NetNet already located for the
2213 * PEIdent name. The midx and lidx arguments are loaded with the
2214 * results, which may be the whole vector, or a single bit, or
2215 * anything in between. The values are in canonical indices.
2217 bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
2218 unsigned&midx, unsigned&lidx) const
2220 const name_component_t&name_tail = path_.back();
2221 // Only treat as part/bit selects any index that is beyond the
2222 // word selects for an array. This is not an array, then
2223 // dimensions==0 and any index is treated as a select.
2224 if (name_tail.index.size() <= sig->array_dimensions()) {
2225 midx = sig->vector_width()-1;
2226 lidx = 0;
2227 return true;
2230 ivl_assert(*this, !name_tail.index.empty());
2232 const index_component_t&index_tail = name_tail.index.back();
2234 switch (index_tail.sel) {
2235 default:
2236 cerr << get_line() << ": internal error: "
2237 << "Unexpected sel_ value = " << index_tail.sel << endl;
2238 ivl_assert(*this, 0);
2239 break;
2241 case index_component_t::SEL_IDX_DO:
2242 case index_component_t::SEL_IDX_UP: {
2243 NetExpr*tmp_ex = elab_and_eval(des, scope, index_tail.msb, -1);
2244 NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex);
2245 if (!tmp) {
2246 cerr << get_line() << ": error: indexed part select of "
2247 << sig->name()
2248 << " must be a constant in this context." << endl;
2249 des->errors += 1;
2250 return 0;
2253 long midx_val = tmp->value().as_long();
2254 midx = sig->sb_to_idx(midx_val);
2255 delete tmp_ex;
2257 /* The width (a constant) is calculated here. */
2258 unsigned long wid = 0;
2259 bool flag = calculate_up_do_width_(des, scope, wid);
2260 if (! flag)
2261 return false;
2263 if (index_tail.sel == index_component_t::SEL_IDX_UP)
2264 lidx = sig->sb_to_idx(midx_val+wid-1);
2265 else
2266 lidx = sig->sb_to_idx(midx_val-wid+1);
2268 if (midx < lidx) {
2269 long tmp = midx;
2270 midx = lidx;
2271 lidx = tmp;
2274 break;
2277 case index_component_t::SEL_PART: {
2279 long msb, lsb;
2280 bool flag = calculate_parts_(des, scope, msb, lsb);
2281 #if 0
2282 NetExpr*tmp_ex = elab_and_eval(des, scope, index_tail.msb, -1);
2283 NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex);
2284 assert(tmp);
2286 long midx_val = tmp->value().as_long();
2287 midx = sig->sb_to_idx(midx_val);
2288 delete tmp_ex;
2290 tmp_ex = elab_and_eval(des, scope, index_tail.lsb, -1);
2291 tmp = dynamic_cast<NetEConst*>(tmp_ex);
2292 if (tmp == 0) {
2293 cerr << get_line() << ": internal error: "
2294 << "lsb expression is not constant?: "
2295 << *tmp_ex << ", " << *index_tail.lsb << endl;
2297 assert(tmp);
2299 long lidx_val = tmp->value().as_long();
2300 lidx = sig->sb_to_idx(lidx_val);
2301 delete tmp_ex;
2302 #endif
2303 lidx = sig->sb_to_idx(lsb);
2304 midx = sig->sb_to_idx(msb);
2305 /* Detect reversed indices of a part select. */
2306 if (lidx > midx) {
2307 cerr << get_line() << ": error: Part select "
2308 << sig->name() << "[" << msb << ":"
2309 << lsb << "] indices reversed." << endl;
2310 cerr << get_line() << ": : Did you mean "
2311 << sig->name() << "[" << lsb << ":"
2312 << msb << "]?" << endl;
2313 unsigned tmp = midx;
2314 midx = lidx;
2315 lidx = tmp;
2316 des->errors += 1;
2319 /* Detect a part select out of range. */
2320 if (midx >= sig->vector_width()) {
2321 cerr << get_line() << ": error: Part select "
2322 << sig->name() << "[" << msb << ":"
2323 << lsb << "] out of range." << endl;
2324 midx = sig->vector_width() - 1;
2325 lidx = 0;
2326 des->errors += 1;
2328 break;
2331 case index_component_t::SEL_BIT:
2332 if (name_tail.index.size() > sig->array_dimensions()) {
2333 verinum*mval = index_tail.msb->eval_const(des, scope);
2334 if (mval == 0) {
2335 cerr << get_line() << ": error: Index of " << path_ <<
2336 " needs to be constant in this context." <<
2337 endl;
2338 cerr << get_line() << ": : Index expression is: "
2339 << *index_tail.msb << endl;
2340 cerr << get_line() << ": : Context scope is: "
2341 << scope_path(scope) << endl;
2342 des->errors += 1;
2343 return false;
2345 assert(mval);
2347 midx = sig->sb_to_idx(mval->as_long());
2348 if (midx >= sig->vector_width()) {
2349 cerr << get_line() << ": error: Index " << sig->name()
2350 << "[" << mval->as_long() << "] out of range."
2351 << endl;
2352 des->errors += 1;
2353 midx = 0;
2355 lidx = midx;
2357 } else {
2358 cerr << get_line() << ": internal error: "
2359 << "Bit select " << path_ << endl;
2360 ivl_assert(*this, 0);
2361 midx = sig->vector_width() - 1;
2362 lidx = 0;
2364 break;
2367 return true;
2371 * This is the common code for l-value nets and bi-directional
2372 * nets. There is very little that is different between the two cases,
2373 * so most of the work for both is done here.
2375 NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
2376 bool implicit_net_ok,
2377 bool bidirectional_flag) const
2379 assert(scope);
2381 NetNet* sig = 0;
2382 const NetExpr*par = 0;
2383 NetEvent* eve = 0;
2385 symbol_search(des, scope, path_, sig, par, eve);
2387 if (eve != 0) {
2388 cerr << get_line() << ": error: named events (" << path_
2389 << ") cannot be l-values in continuous "
2390 << "assignments." << endl;
2391 des->errors += 1;
2392 return 0;
2395 if (sig == 0) {
2397 if (implicit_net_ok) {
2399 sig = make_implicit_net_(des, scope);
2400 if (sig == 0)
2401 return 0;
2403 } else {
2404 cerr << get_line() << ": error: Net " << path_
2405 << " is not defined in this context." << endl;
2406 des->errors += 1;
2407 return 0;
2411 assert(sig);
2413 /* Don't allow registers as assign l-values. */
2414 if (sig->type() == NetNet::REG) {
2415 cerr << get_line() << ": error: reg " << sig->name()
2416 << "; cannot be driven by primitives"
2417 << " or continuous assignment." << endl;
2418 des->errors += 1;
2419 return 0;
2422 if (sig->port_type() == NetNet::PINPUT) {
2423 cerr << get_line() << ": warning: L-value ``"
2424 << sig->name() << "'' is also an input port." << endl;
2425 cerr << sig->get_line() << ": warning: input "
2426 << sig->name() << "; is coerced to inout." << endl;
2427 sig->port_type(NetNet::PINOUT);
2430 // Default part select is the entire word.
2431 unsigned midx = sig->vector_width()-1, lidx = 0;
2432 // The default word select is the first.
2433 unsigned widx = 0;
2435 const name_component_t&name_tail = path_.back();
2437 if (sig->array_dimensions() > 0) {
2439 if (name_tail.index.empty()) {
2440 cerr << get_line() << ": error: array " << sig->name()
2441 << " must be used with an index." << endl;
2442 des->errors += 1;
2443 return 0;
2446 const index_component_t&index_head = name_tail.index.front();
2447 if (index_head.sel == index_component_t::SEL_PART) {
2448 cerr << get_line() << ": error: cannot perform a part "
2449 << "select on array " << sig->name() << "." << endl;
2450 des->errors += 1;
2451 return 0;
2453 ivl_assert(*this, index_head.sel == index_component_t::SEL_BIT);
2455 NetExpr*tmp_ex = elab_and_eval(des, scope, index_head.msb, -1);
2456 NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex);
2457 if (!tmp) {
2458 cerr << get_line() << ": error: array " << sig->name()
2459 << " index must be a constant in this context." << endl;
2460 des->errors += 1;
2461 return 0;
2464 long widx_val = tmp->value().as_long();
2465 widx = sig->array_index_to_address(widx_val);
2466 delete tmp_ex;
2468 if (debug_elaborate)
2469 cerr << get_line() << ": debug: Use [" << widx << "]"
2470 << " to index l-value array." << endl;
2472 /* The array has a part/bit select at the end. */
2473 if (name_tail.index.size() > sig->array_dimensions()) {
2474 if (! eval_part_select_(des, scope, sig, midx, lidx))
2475 return 0;
2477 } else if (!name_tail.index.empty()) {
2478 if (! eval_part_select_(des, scope, sig, midx, lidx))
2479 return 0;
2482 unsigned subnet_wid = midx-lidx+1;
2484 if (sig->pin_count() > 1) {
2485 assert(widx < sig->pin_count());
2487 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
2488 sig->type(), sig->vector_width());
2489 tmp->set_line(*this);
2490 tmp->local_flag(true);
2491 connect(sig->pin(widx), tmp->pin(0));
2492 sig = tmp;
2495 /* If the desired l-value vector is narrower then the
2496 signal itself, then use a NetPartSelect node to
2497 arrange for connection to the desired bits. All this
2498 can be skipped if the desired with matches the
2499 original vector. */
2501 if (subnet_wid != sig->vector_width()) {
2502 /* If we are processing a tran or inout, then the
2503 partselect is bi-directional. Otherwise, it is a
2504 Part-to-Vector select. */
2505 NetPartSelect::dir_t part_dir;
2506 if (bidirectional_flag)
2507 part_dir = NetPartSelect::BI;
2508 else
2509 part_dir = NetPartSelect::PV;
2511 if (debug_elaborate)
2512 cerr << get_line() << ": debug: "
2513 << "Elaborate lnet part select "
2514 << sig->name()
2515 << "[base=" << lidx
2516 << " wid=" << subnet_wid <<"]"
2517 << endl;
2519 NetNet*subsig = new NetNet(sig->scope(),
2520 sig->scope()->local_symbol(),
2521 NetNet::WIRE, subnet_wid);
2522 subsig->data_type( sig->data_type() );
2523 subsig->local_flag(true);
2524 subsig->set_line(*this);
2526 NetPartSelect*sub = new NetPartSelect(sig, lidx, subnet_wid,
2527 part_dir);
2528 des->add_node(sub);
2529 connect(sub->pin(0), subsig->pin(0));
2531 sig = subsig;
2534 return sig;
2538 * Identifiers in continuous assignment l-values are limited to wires
2539 * and that ilk. Detect registers and memories here and report errors.
2541 NetNet* PEIdent::elaborate_lnet(Design*des, NetScope*scope,
2542 bool implicit_net_ok) const
2544 return elaborate_lnet_common_(des, scope, implicit_net_ok, false);
2547 NetNet* PEIdent::elaborate_bi_net(Design*des, NetScope*scope) const
2549 return elaborate_lnet_common_(des, scope, true, true);
2553 * This method is used to elaborate identifiers that are ports to a
2554 * scope. The scope is presumed to be that of the module that has the
2555 * port. This elaboration is done inside the module, and is only done
2556 * to PEIdent objects. This method is used by elaboration of a module
2557 * instantiation (PGModule::elaborate_mod_) to get NetNet objects for
2558 * the port.
2560 NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
2562 NetNet*sig = des->find_signal(scope, path_);
2563 if (sig == 0) {
2564 cerr << get_line() << ": error: no wire/reg " << path_
2565 << " in module " << scope_path(scope) << "." << endl;
2566 des->errors += 1;
2567 return 0;
2570 /* Check the port_type of the signal to make sure it is really
2571 a port, and its direction is resolved. */
2572 switch (sig->port_type()) {
2573 case NetNet::PINPUT:
2574 case NetNet::POUTPUT:
2575 case NetNet::PINOUT:
2576 break;
2578 /* If the name matches, but the signal is not a port,
2579 then the user declared the object but there is no
2580 matching input/output/inout declaration. */
2582 case NetNet::NOT_A_PORT:
2583 cerr << get_line() << ": error: signal " << path_ << " in"
2584 << " module " << scope_path(scope) << " is not a port." << endl;
2585 cerr << get_line() << ": : Are you missing an input/"
2586 << "output/inout declaration?" << endl;
2587 des->errors += 1;
2588 return 0;
2590 /* This should not happen. A PWire can only become
2591 PIMPLICIT if this is a udp reg port, and the make_udp
2592 function should turn it into an output.... I think. */
2594 case NetNet::PIMPLICIT:
2595 cerr << get_line() << ": internal error: signal " << path_
2596 << " in module " << scope_path(scope) << " is left as "
2597 << "port type PIMPLICIT." << endl;
2598 des->errors += 1;
2599 return 0;
2602 unsigned midx;
2603 unsigned lidx;
2605 /* Evaluate the part/bit select expressions, to get the part
2606 select of the signal that attaches to the port. Also handle
2607 range and direction checking here. */
2609 if (! eval_part_select_(des, scope, sig, midx, lidx))
2610 return 0;
2613 unsigned swid = midx - lidx + 1;
2615 if (swid < sig->vector_width()) {
2616 cerr << get_line() << ": XXXX: Forgot to implement part select"
2617 << " of signal port." << endl;
2620 return sig;
2624 * Elaborate a number as a NetConst object.
2626 * The code assumes that the result is IVL_VT_LOGIC.
2628 NetNet* PENumber::elaborate_net(Design*des, NetScope*scope,
2629 unsigned lwidth,
2630 const NetExpr* rise,
2631 const NetExpr* fall,
2632 const NetExpr* decay,
2633 Link::strength_t drive0,
2634 Link::strength_t drive1) const
2637 /* If we are constrained by a l-value size, then just make a
2638 number constant with the correct size and set as many bits
2639 in that constant as make sense. Pad excess with
2640 zeros. Also, assume that numbers are meant to be logic
2641 type. */
2643 if (lwidth > 0) {
2644 NetNet*net = new NetNet(scope, scope->local_symbol(),
2645 NetNet::IMPLICIT, lwidth);
2646 net->data_type(IVL_VT_LOGIC);
2647 net->local_flag(true);
2648 net->set_signed(value_->has_sign());
2650 verinum num = pad_to_width(*value_, lwidth);
2651 if (num.len() > lwidth)
2652 num = verinum(num, lwidth);
2654 NetConst*tmp = new NetConst(scope, scope->local_symbol(), num);
2655 tmp->pin(0).drive0(drive0);
2656 tmp->pin(0).drive1(drive1);
2657 connect(net->pin(0), tmp->pin(0));
2659 des->add_node(tmp);
2660 return net;
2663 /* If the number has a length, then use that to size the
2664 number. Generate a constant object of exactly the user
2665 specified size. */
2666 if (value_->has_len()) {
2667 NetNet*net = new NetNet(scope, scope->local_symbol(),
2668 NetNet::IMPLICIT, value_->len());
2669 net->data_type(IVL_VT_LOGIC);
2670 net->local_flag(true);
2671 net->set_signed(value_->has_sign());
2672 NetConst*tmp = new NetConst(scope, scope->local_symbol(),
2673 *value_);
2674 connect(net->pin(0), tmp->pin(0));
2676 des->add_node(tmp);
2677 return net;
2680 /* None of the above tight constraints are present, so make a
2681 plausible choice for the width. Try to reduce the width as
2682 much as possible by eliminating high zeros of unsigned
2683 numbers. */
2685 if (must_be_self_determined_flag) {
2686 cerr << get_line() << ": error: No idea how wide to make "
2687 << "the unsized constant " << *value_ << "." << endl;
2688 des->errors += 1;
2691 unsigned width = value_->len();
2693 if (value_->has_sign() && (value_->get(width-1) == verinum::V0)) {
2695 /* If the number is signed, but known to be positive,
2696 then reduce it down as if it were unsigned. */
2697 while (width > 1) {
2698 if (value_->get(width-1) != verinum::V0)
2699 break;
2700 width -= 1;
2703 } else if (value_->has_sign() == false) {
2704 while ( (width > 1) && (value_->get(width-1) == verinum::V0))
2705 width -= 1;
2708 verinum num (verinum::V0, width);
2709 for (unsigned idx = 0 ; idx < width ; idx += 1)
2710 num.set(idx, value_->get(idx));
2712 NetNet*net = new NetNet(scope, scope->local_symbol(),
2713 NetNet::IMPLICIT, width);
2714 net->data_type(IVL_VT_LOGIC);
2715 net->local_flag(true);
2716 NetConst*tmp = new NetConst(scope, scope->local_symbol(), num);
2717 connect(net->pin(0), tmp->pin(0));
2719 des->add_node(tmp);
2720 return net;
2724 * A string is a NetEConst node that is made of the ASCII bits of the
2725 * string instead of the bits of a number. In fact, a string is just
2726 * another numeric notation.
2728 NetNet* PEString::elaborate_net(Design*des, NetScope*scope,
2729 unsigned lwidth,
2730 const NetExpr* rise,
2731 const NetExpr* fall,
2732 const NetExpr* decay,
2733 Link::strength_t drive0,
2734 Link::strength_t drive1) const
2736 unsigned strbits = strlen(text_) * 8;
2737 NetNet*net;
2739 /* If we are constrained by a l-value size, then just make a
2740 number constant with the correct size and set as many bits
2741 in that constant as make sense. Pad excess with zeros. */
2742 if (lwidth > 0) {
2743 net = new NetNet(scope, scope->local_symbol(),
2744 NetNet::IMPLICIT, lwidth);
2746 } else {
2747 net = new NetNet(scope, scope->local_symbol(),
2748 NetNet::IMPLICIT, strbits);
2750 net->data_type(IVL_VT_BOOL);
2751 net->local_flag(true);
2753 /* Make a verinum that is filled with the 0 pad. */
2754 verinum num(verinum::V0, net->vector_width());
2756 unsigned idx;
2757 for (idx = 0 ; idx < num.len() && idx < strbits; idx += 1) {
2758 char byte = text_[strbits/8 - 1 - idx/8];
2759 char mask = 1<<(idx%8);
2760 num.set(idx, (byte & mask)? verinum::V1 : verinum::V0);
2763 NetConst*tmp = new NetConst(scope, scope->local_symbol(), num);
2764 tmp->set_line(*this);
2765 des->add_node(tmp);
2767 connect(net->pin(0), tmp->pin(0));
2769 return net;
2773 * Elaborate the ternary operator in a netlist by creating a LPM_MUX
2774 * with width matching the result, size == 2 and 1 select input. These
2775 * expressions come from code like:
2777 * res = test ? a : b;
2779 * The res has the width requested of this method, and the a and b
2780 * expressions have their own similar widths. The test expression is
2781 * only a single bit wide. The output from this function is a NetNet
2782 * object the width of the <res> expression and connected to the
2783 * Result pins of the LPM_MUX device. Any width not covered by the
2784 * width of the mux is padded with a NetConst device.
2786 NetNet* PETernary::elaborate_net(Design*des, NetScope*scope,
2787 unsigned width,
2788 const NetExpr* rise,
2789 const NetExpr* fall,
2790 const NetExpr* decay,
2791 Link::strength_t drive0,
2792 Link::strength_t drive1) const
2794 NetNet* expr_sig = expr_->elaborate_net(des, scope, 0, 0, 0, 0);
2795 NetNet* tru_sig = tru_->elaborate_net(des, scope, width, 0, 0, 0);
2796 NetNet* fal_sig = fal_->elaborate_net(des, scope, width, 0, 0, 0);
2797 if (expr_sig == 0 || tru_sig == 0 || fal_sig == 0) {
2798 des->errors += 1;
2799 return 0;
2802 /* The type of the true and false expressions must
2803 match. These become the type of the resulting
2804 expression. */
2806 ivl_variable_type_t expr_type = tru_sig->data_type();
2808 if (tru_sig->data_type() != fal_sig->data_type()) {
2809 cerr << get_line() << ": error: True and False clauses of"
2810 << " ternary expression have differnt types." << endl;
2811 cerr << get_line() << ": : True clause is "
2812 << tru_sig->data_type() << ", false clause is "
2813 << fal_sig->data_type() << "." << endl;
2815 des->errors += 1;
2816 expr_type = IVL_VT_NO_TYPE;
2818 } else if (expr_type == IVL_VT_NO_TYPE) {
2819 cerr << get_line() << ": internal error: True and false "
2820 << "clauses of ternary both have NO TYPE." << endl;
2821 des->errors += 1;
2824 /* The natural width of the expression is the width of the
2825 largest condition. Normally they should be the same size,
2826 but if we do not get a size from the context, or the
2827 expressions resist, we need to cope. */
2828 unsigned iwidth = tru_sig->vector_width();
2829 if (fal_sig->vector_width() > iwidth)
2830 iwidth = fal_sig->vector_width();
2833 /* If the width is not passed from the context, then take the
2834 widest result as our width. */
2835 if (width == 0)
2836 width = iwidth;
2838 /* If the expression has width, then generate a boolean result
2839 by connecting an OR gate to calculate the truth value of
2840 the result. In the end, the result needs to be a single bit. */
2841 if (expr_sig->vector_width() > 1) {
2842 NetUReduce*log = new NetUReduce(scope, scope->local_symbol(),
2843 NetUReduce::OR,
2844 expr_sig->vector_width());
2845 log->set_line(*this);
2846 des->add_node(log);
2847 connect(log->pin(1), expr_sig->pin(0));
2849 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
2850 NetNet::IMPLICIT, 1);
2851 tmp->data_type(IVL_VT_LOGIC);
2852 tmp->local_flag(true);
2853 connect(log->pin(0), tmp->pin(0));
2855 expr_sig = tmp;
2858 assert(expr_sig->vector_width() == 1);
2860 /* This is the width of the LPM_MUX device that I'm about to
2861 create. It may be smaller then the desired output, but I'll
2862 handle padding below. Note that in principle the
2863 alternatives should be padded to the output width first,
2864 but it is more efficient to pad them only just enough to
2865 prevent loss, and do the finished padding later.
2867 Create a NetNet object wide enough to hold the
2868 result. Also, pad the result values (if necessary) so that
2869 the mux inputs can be fully connected. */
2871 unsigned dwidth = (iwidth > width)? width : iwidth;
2873 NetNet*sig = new NetNet(scope, scope->local_symbol(),
2874 NetNet::WIRE, dwidth);
2875 sig->data_type(expr_type);
2876 sig->local_flag(true);
2878 if (fal_sig->vector_width() < dwidth)
2879 fal_sig = pad_to_width(des, fal_sig, dwidth);
2881 if (tru_sig->vector_width() < dwidth)
2882 tru_sig = pad_to_width(des, tru_sig, dwidth);
2884 if (dwidth < fal_sig->vector_width())
2885 fal_sig = crop_to_width(des, fal_sig, dwidth);
2887 if (dwidth < tru_sig->vector_width())
2888 tru_sig = crop_to_width(des, tru_sig, dwidth);
2890 /* Make the device and connect its outputs to the osig and
2891 inputs to the tru and false case nets. Also connect the
2892 selector bit to the sel input.
2894 The inputs are the 0 (false) connected to fal_sig and 1
2895 (true) connected to tru_sig. */
2897 NetMux*mux = new NetMux(scope, scope->local_symbol(), dwidth, 2, 1);
2898 connect(mux->pin_Sel(), expr_sig->pin(0));
2900 /* Connect the data inputs. */
2901 connect(mux->pin_Data(0), fal_sig->pin(0));
2902 connect(mux->pin_Data(1), tru_sig->pin(0));
2904 /* If there are non-zero output delays, then create bufz
2905 devices to carry the propagation delays. Otherwise, just
2906 connect the result to the output. */
2907 if (rise || fall || decay) {
2908 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
2909 NetNet::WIRE, dwidth);
2910 tmp->data_type(expr_type);
2911 tmp->local_flag(true);
2913 NetBUFZ*tmpz = new NetBUFZ(scope, scope->local_symbol(), dwidth);
2914 tmpz->rise_time(rise);
2915 tmpz->fall_time(fall);
2916 tmpz->decay_time(decay);
2917 tmpz->pin(0).drive0(drive0);
2918 tmpz->pin(0).drive1(drive1);
2920 connect(mux->pin_Result(), tmp->pin(0));
2921 connect(tmp->pin(0), tmpz->pin(1));
2922 connect(sig->pin(0), tmpz->pin(0));
2924 des->add_node(tmpz);
2926 } else {
2927 connect(mux->pin_Result(), sig->pin(0));
2930 /* If the MUX device result is too narrow to fill out the
2931 desired result, pad with zeros... */
2932 assert(dwidth <= width);
2934 des->add_node(mux);
2936 /* If the MUX device results is too narrow to fill out the
2937 desired result, then pad it. It is OK to have a too-narrow
2938 result here because the dwidth choice is >= the width of
2939 both alternatives. Thus, padding here is equivalent to
2940 padding inside, and is cheaper. */
2941 if (dwidth < width)
2942 sig = pad_to_width(des, sig, width);
2944 return sig;
2947 NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
2948 unsigned width,
2949 const NetExpr* rise,
2950 const NetExpr* fall,
2951 const NetExpr* decay,
2952 Link::strength_t drive0,
2953 Link::strength_t drive1) const
2956 // Some unary operands allow the operand to be
2957 // self-determined, and some do not.
2958 unsigned owidth = 0;
2959 switch (op_) {
2960 case '~':
2961 case '-':
2962 owidth = width;
2963 break;
2966 NetNet* sig = 0;
2967 NetLogic*gate;
2970 // Handle the special case of a 2's complement of a constant
2971 // value. This can be reduced to a no-op on a precalculated
2972 // result.
2973 if (op_ == '-') do {
2974 // TODO: Should replace this with a call to
2975 // elab_and_eval. Possibly blend this with the rest of
2976 // the elaboration as well.
2977 verinum*val = expr_->eval_const(des, scope);
2978 if (val == 0)
2979 break;
2981 if (width == 0)
2982 width = val->len();
2984 assert(width > 0);
2985 sig = new NetNet(scope, scope->local_symbol(),
2986 NetNet::WIRE, width);
2987 sig->data_type(IVL_VT_LOGIC);
2988 sig->local_flag(true);
2990 /* Take the 2s complement by taking the 1s complement
2991 and adding 1. */
2992 verinum tmp (v_not(*val), width);
2993 verinum one (1UL, width);
2994 tmp = verinum(tmp + one, width);
2995 tmp.has_sign(val->has_sign());
2997 NetConst*con = new NetConst(scope, scope->local_symbol(), tmp);
2998 connect(sig->pin(0), con->pin(0));
3000 if (debug_elaborate) {
3001 cerr << get_line() << ": debug: Replace expression "
3002 << *this << " with constant " << tmp << "."<<endl;
3005 delete val;
3006 des->add_node(con);
3007 return sig;
3009 } while (0);
3011 NetNet* sub_sig = expr_->elaborate_net(des, scope, owidth, 0, 0, 0);
3012 if (sub_sig == 0) {
3013 des->errors += 1;
3014 return 0;
3016 assert(sub_sig);
3018 bool reduction=false;
3019 NetUReduce::TYPE rtype = NetUReduce::NONE;
3021 switch (op_) {
3022 case '~': // Bitwise NOT
3023 sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE,
3024 sub_sig->vector_width());
3025 sig->data_type(sub_sig->data_type());
3026 sig->local_flag(true);
3027 gate = new NetLogic(scope, scope->local_symbol(),
3028 2, NetLogic::NOT, sub_sig->vector_width());
3029 gate->set_line(*this);
3030 des->add_node(gate);
3031 gate->rise_time(rise);
3032 gate->fall_time(fall);
3033 gate->decay_time(decay);
3035 connect(gate->pin(1), sub_sig->pin(0));
3036 connect(gate->pin(0), sig->pin(0));
3037 break;
3039 case 'N': // Reduction NOR
3040 case '!': // Reduction NOT
3041 reduction=true; rtype = NetUReduce::NOR; break;
3042 case '&': // Reduction AND
3043 reduction=true; rtype = NetUReduce::AND; break;
3044 case '|': // Reduction OR
3045 reduction=true; rtype = NetUReduce::OR; break;
3046 case '^': // Reduction XOR
3047 reduction=true; rtype = NetUReduce::XOR; break;
3048 case 'A': // Reduction NAND (~&)
3049 reduction=true; rtype = NetUReduce::NAND; break;
3050 case 'X': // Reduction XNOR (~^)
3051 reduction=true; rtype = NetUReduce::XNOR; break;
3053 case '-': // Unary 2's complement.
3054 // If this expression is self determined, get its width
3055 // from the sub_expression.
3056 if (owidth == 0)
3057 owidth = sub_sig->vector_width();
3059 sig = new NetNet(scope, scope->local_symbol(),
3060 NetNet::WIRE, owidth);
3061 sig->data_type(sub_sig->data_type());
3062 sig->local_flag(true);
3064 if (sub_sig->vector_width() < owidth)
3065 sub_sig = pad_to_width(des, sub_sig, owidth);
3067 switch (sub_sig->vector_width()) {
3068 case 0:
3069 assert(0);
3070 break;
3072 case 1:
3073 gate = new NetLogic(scope, scope->local_symbol(),
3074 2, NetLogic::BUF, 1);
3075 connect(gate->pin(0), sig->pin(0));
3076 connect(gate->pin(1), sub_sig->pin(0));
3077 des->add_node(gate);
3078 gate->rise_time(rise);
3079 gate->fall_time(fall);
3080 gate->decay_time(decay);
3081 break;
3083 default:
3084 NetAddSub*sub = new NetAddSub(scope, scope->local_symbol(),
3085 sig->vector_width());
3086 sub->attribute(perm_string::literal("LPM_Direction"),
3087 verinum("SUB"));
3089 des->add_node(sub);
3091 connect(sig->pin(0), sub->pin_Result());
3092 connect(sub_sig->pin(0), sub->pin_DataB());
3094 verinum tmp_num (verinum::V0, sub->width(), true);
3095 NetConst*tmp_con = new NetConst(scope,
3096 scope->local_symbol(),
3097 tmp_num);
3098 des->add_node(tmp_con);
3100 NetNet*tmp_sig = new NetNet(scope, scope->local_symbol(),
3101 NetNet::WIRE,
3102 sub_sig->vector_width());
3103 tmp_sig->data_type(sub_sig->data_type());
3104 tmp_sig->local_flag(true);
3106 connect(tmp_sig->pin(0), sub->pin_DataA());
3107 connect(tmp_sig->pin(0), tmp_con->pin(0));
3108 break;
3110 break;
3112 default:
3113 cerr << "internal error: Unhandled UNARY '" << op_ << "'" << endl;
3114 sig = 0;
3117 if (reduction) {
3118 NetUReduce*rgate;
3120 // The output of a reduction operator is 1 bit
3121 sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, 1);
3122 sig->data_type(sub_sig->data_type());
3123 sig->local_flag(true);
3125 rgate = new NetUReduce(scope, scope->local_symbol(),
3126 rtype, sub_sig->vector_width());
3127 rgate->set_line(*this);
3128 connect(rgate->pin(0), sig->pin(0));
3129 connect(rgate->pin(1), sub_sig->pin(0));
3131 des->add_node(rgate);
3132 rgate->rise_time(rise);
3133 rgate->fall_time(fall);
3134 rgate->decay_time(decay);
3137 return sig;