Compile time warnings
[iverilog.git] / elab_net.cc
blobb39a494979617ccd06cbc99ac055284a4d588763
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 ivl_assert(*this, tmp);
2247 long midx_val = tmp->value().as_long();
2248 midx = sig->sb_to_idx(midx_val);
2249 delete tmp_ex;
2251 /* The width (a constant) is calculated here. */
2252 unsigned long wid = 0;
2253 bool flag = calculate_up_do_width_(des, scope, wid);
2254 if (! flag)
2255 return false;
2257 if (index_tail.sel == index_component_t::SEL_IDX_UP)
2258 lidx = sig->sb_to_idx(midx_val+wid-1);
2259 else
2260 lidx = sig->sb_to_idx(midx_val-wid+1);
2262 if (midx < lidx) {
2263 long tmp = midx;
2264 midx = lidx;
2265 lidx = tmp;
2268 break;
2271 case index_component_t::SEL_PART: {
2273 long msb, lsb;
2274 bool flag = calculate_parts_(des, scope, msb, lsb);
2275 #if 0
2276 NetExpr*tmp_ex = elab_and_eval(des, scope, index_tail.msb, -1);
2277 NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex);
2278 assert(tmp);
2280 long midx_val = tmp->value().as_long();
2281 midx = sig->sb_to_idx(midx_val);
2282 delete tmp_ex;
2284 tmp_ex = elab_and_eval(des, scope, index_tail.lsb, -1);
2285 tmp = dynamic_cast<NetEConst*>(tmp_ex);
2286 if (tmp == 0) {
2287 cerr << get_line() << ": internal error: "
2288 << "lsb expression is not constant?: "
2289 << *tmp_ex << ", " << *index_tail.lsb << endl;
2291 assert(tmp);
2293 long lidx_val = tmp->value().as_long();
2294 lidx = sig->sb_to_idx(lidx_val);
2295 delete tmp_ex;
2296 #endif
2297 lidx = sig->sb_to_idx(lsb);
2298 midx = sig->sb_to_idx(msb);
2299 /* Detect reversed indices of a part select. */
2300 if (lidx > midx) {
2301 cerr << get_line() << ": error: Part select "
2302 << sig->name() << "[" << msb << ":"
2303 << lsb << "] indices reversed." << endl;
2304 cerr << get_line() << ": : Did you mean "
2305 << sig->name() << "[" << lsb << ":"
2306 << msb << "]?" << endl;
2307 unsigned tmp = midx;
2308 midx = lidx;
2309 lidx = tmp;
2310 des->errors += 1;
2313 /* Detect a part select out of range. */
2314 if (midx >= sig->vector_width()) {
2315 cerr << get_line() << ": error: Part select "
2316 << sig->name() << "[" << msb << ":"
2317 << lsb << "] out of range." << endl;
2318 midx = sig->vector_width() - 1;
2319 lidx = 0;
2320 des->errors += 1;
2322 break;
2325 case index_component_t::SEL_BIT:
2326 if (name_tail.index.size() > sig->array_dimensions()) {
2327 verinum*mval = index_tail.msb->eval_const(des, scope);
2328 if (mval == 0) {
2329 cerr << get_line() << ": error: Index of " << path_ <<
2330 " needs to be constant in this context." <<
2331 endl;
2332 cerr << get_line() << ": : Index expression is: "
2333 << *index_tail.msb << endl;
2334 cerr << get_line() << ": : Context scope is: "
2335 << scope_path(scope) << endl;
2336 des->errors += 1;
2337 return false;
2339 assert(mval);
2341 midx = sig->sb_to_idx(mval->as_long());
2342 if (midx >= sig->vector_width()) {
2343 cerr << get_line() << ": error: Index " << sig->name()
2344 << "[" << mval->as_long() << "] out of range."
2345 << endl;
2346 des->errors += 1;
2347 midx = 0;
2349 lidx = midx;
2351 } else {
2352 cerr << get_line() << ": internal error: "
2353 << "Bit select " << path_ << endl;
2354 ivl_assert(*this, 0);
2355 midx = sig->vector_width() - 1;
2356 lidx = 0;
2358 break;
2361 return true;
2365 * This is the common code for l-value nets and bi-directional
2366 * nets. There is very little that is different between the two cases,
2367 * so most of the work for both is done here.
2369 NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
2370 bool implicit_net_ok,
2371 bool bidirectional_flag) const
2373 assert(scope);
2375 NetNet* sig = 0;
2376 const NetExpr*par = 0;
2377 NetEvent* eve = 0;
2379 symbol_search(des, scope, path_, sig, par, eve);
2381 if (eve != 0) {
2382 cerr << get_line() << ": error: named events (" << path_
2383 << ") cannot be l-values in continuous "
2384 << "assignments." << endl;
2385 des->errors += 1;
2386 return 0;
2389 if (sig == 0) {
2391 if (implicit_net_ok) {
2393 sig = make_implicit_net_(des, scope);
2394 if (sig == 0)
2395 return 0;
2397 } else {
2398 cerr << get_line() << ": error: Net " << path_
2399 << " is not defined in this context." << endl;
2400 des->errors += 1;
2401 return 0;
2405 assert(sig);
2407 /* Don't allow registers as assign l-values. */
2408 if (sig->type() == NetNet::REG) {
2409 cerr << get_line() << ": error: reg " << sig->name()
2410 << "; cannot be driven by primitives"
2411 << " or continuous assignment." << endl;
2412 des->errors += 1;
2413 return 0;
2416 if (sig->port_type() == NetNet::PINPUT) {
2417 cerr << get_line() << ": warning: L-value ``"
2418 << sig->name() << "'' is also an input port." << endl;
2419 cerr << sig->get_line() << ": warning: input "
2420 << sig->name() << "; is coerced to inout." << endl;
2421 sig->port_type(NetNet::PINOUT);
2424 // Default part select is the entire word.
2425 unsigned midx = sig->vector_width()-1, lidx = 0;
2426 // The default word select is the first.
2427 unsigned widx = 0;
2429 const name_component_t&name_tail = path_.back();
2431 if (sig->array_dimensions() > 0) {
2433 ivl_assert(*this, !name_tail.index.empty());
2435 const index_component_t&index_head = name_tail.index.front();
2436 ivl_assert(*this, index_head.sel == index_component_t::SEL_BIT);
2438 NetExpr*tmp_ex = elab_and_eval(des, scope, index_head.msb, -1);
2439 NetEConst*tmp = dynamic_cast<NetEConst*>(tmp_ex);
2440 assert(tmp);
2442 long widx_val = tmp->value().as_long();
2443 widx = sig->array_index_to_address(widx_val);
2444 delete tmp_ex;
2446 if (debug_elaborate)
2447 cerr << get_line() << ": debug: Use [" << widx << "]"
2448 << " to index l-value array." << endl;
2450 } else if (!name_tail.index.empty()) {
2451 if (! eval_part_select_(des, scope, sig, midx, lidx))
2452 return 0;
2455 unsigned subnet_wid = midx-lidx+1;
2457 if (sig->pin_count() > 1) {
2458 assert(widx < sig->pin_count());
2460 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
2461 sig->type(), sig->vector_width());
2462 tmp->set_line(*this);
2463 tmp->local_flag(true);
2464 connect(sig->pin(widx), tmp->pin(0));
2465 sig = tmp;
2468 /* If the desired l-value vector is narrower then the
2469 signal itself, then use a NetPartSelect node to
2470 arrange for connection to the desired bits. All this
2471 can be skipped if the desired with matches the
2472 original vector. */
2474 if (subnet_wid != sig->vector_width()) {
2475 /* If we are processing a tran or inout, then the
2476 partselect is bi-directional. Otherwise, it is a
2477 Part-to-Vector select. */
2478 NetPartSelect::dir_t part_dir;
2479 if (bidirectional_flag)
2480 part_dir = NetPartSelect::BI;
2481 else
2482 part_dir = NetPartSelect::PV;
2484 if (debug_elaborate)
2485 cerr << get_line() << ": debug: "
2486 << "Elaborate lnet part select "
2487 << sig->name()
2488 << "[base=" << lidx
2489 << " wid=" << subnet_wid <<"]"
2490 << endl;
2492 NetNet*subsig = new NetNet(sig->scope(),
2493 sig->scope()->local_symbol(),
2494 NetNet::WIRE, subnet_wid);
2495 subsig->data_type( sig->data_type() );
2496 subsig->local_flag(true);
2497 subsig->set_line(*this);
2499 NetPartSelect*sub = new NetPartSelect(sig, lidx, subnet_wid,
2500 part_dir);
2501 des->add_node(sub);
2502 connect(sub->pin(0), subsig->pin(0));
2504 sig = subsig;
2507 return sig;
2511 * Identifiers in continuous assignment l-values are limited to wires
2512 * and that ilk. Detect registers and memories here and report errors.
2514 NetNet* PEIdent::elaborate_lnet(Design*des, NetScope*scope,
2515 bool implicit_net_ok) const
2517 return elaborate_lnet_common_(des, scope, implicit_net_ok, false);
2520 NetNet* PEIdent::elaborate_bi_net(Design*des, NetScope*scope) const
2522 return elaborate_lnet_common_(des, scope, true, true);
2526 * This method is used to elaborate identifiers that are ports to a
2527 * scope. The scope is presumed to be that of the module that has the
2528 * port. This elaboration is done inside the module, and is only done
2529 * to PEIdent objects. This method is used by elaboration of a module
2530 * instantiation (PGModule::elaborate_mod_) to get NetNet objects for
2531 * the port.
2533 NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
2535 NetNet*sig = des->find_signal(scope, path_);
2536 if (sig == 0) {
2537 cerr << get_line() << ": error: no wire/reg " << path_
2538 << " in module " << scope_path(scope) << "." << endl;
2539 des->errors += 1;
2540 return 0;
2543 /* Check the port_type of the signal to make sure it is really
2544 a port, and its direction is resolved. */
2545 switch (sig->port_type()) {
2546 case NetNet::PINPUT:
2547 case NetNet::POUTPUT:
2548 case NetNet::PINOUT:
2549 break;
2551 /* If the name matches, but the signal is not a port,
2552 then the user declared the object but there is no
2553 matching input/output/inout declaration. */
2555 case NetNet::NOT_A_PORT:
2556 cerr << get_line() << ": error: signal " << path_ << " in"
2557 << " module " << scope_path(scope) << " is not a port." << endl;
2558 cerr << get_line() << ": : Are you missing an input/"
2559 << "output/inout declaration?" << endl;
2560 des->errors += 1;
2561 return 0;
2563 /* This should not happen. A PWire can only become
2564 PIMPLICIT if this is a udp reg port, and the make_udp
2565 function should turn it into an output.... I think. */
2567 case NetNet::PIMPLICIT:
2568 cerr << get_line() << ": internal error: signal " << path_
2569 << " in module " << scope_path(scope) << " is left as "
2570 << "port type PIMPLICIT." << endl;
2571 des->errors += 1;
2572 return 0;
2575 unsigned midx;
2576 unsigned lidx;
2578 /* Evaluate the part/bit select expressions, to get the part
2579 select of the signal that attaches to the port. Also handle
2580 range and direction checking here. */
2582 if (! eval_part_select_(des, scope, sig, midx, lidx))
2583 return 0;
2586 unsigned swid = midx - lidx + 1;
2588 if (swid < sig->vector_width()) {
2589 cerr << get_line() << ": XXXX: Forgot to implement part select"
2590 << " of signal port." << endl;
2593 return sig;
2597 * Elaborate a number as a NetConst object.
2599 * The code assumes that the result is IVL_VT_LOGIC.
2601 NetNet* PENumber::elaborate_net(Design*des, NetScope*scope,
2602 unsigned lwidth,
2603 const NetExpr* rise,
2604 const NetExpr* fall,
2605 const NetExpr* decay,
2606 Link::strength_t drive0,
2607 Link::strength_t drive1) const
2610 /* If we are constrained by a l-value size, then just make a
2611 number constant with the correct size and set as many bits
2612 in that constant as make sense. Pad excess with
2613 zeros. Also, assume that numbers are meant to be logic
2614 type. */
2616 if (lwidth > 0) {
2617 NetNet*net = new NetNet(scope, scope->local_symbol(),
2618 NetNet::IMPLICIT, lwidth);
2619 net->data_type(IVL_VT_LOGIC);
2620 net->local_flag(true);
2621 net->set_signed(value_->has_sign());
2623 /* when expanding a constant to fit into the net, extend
2624 the Vx or Vz values if they are in the sign position,
2625 otherwise extend the number with 0 bits. */
2626 verinum::V top_v = verinum::V0;
2627 switch (value_->get(value_->len()-1)) {
2628 case verinum::Vx:
2629 top_v = verinum::Vx;
2630 break;
2631 case verinum::Vz:
2632 top_v = verinum::Vz;
2633 break;
2634 default: /* V0 and V1, do nothing */
2635 break;
2638 verinum num(top_v, net->vector_width());
2639 unsigned idx;
2640 for (idx = 0 ; idx < num.len() && idx < value_->len(); idx += 1)
2641 num.set(idx, value_->get(idx));
2643 NetConst*tmp = new NetConst(scope, scope->local_symbol(), num);
2644 tmp->pin(0).drive0(drive0);
2645 tmp->pin(0).drive1(drive1);
2646 connect(net->pin(0), tmp->pin(0));
2648 des->add_node(tmp);
2649 return net;
2652 /* If the number has a length, then use that to size the
2653 number. Generate a constant object of exactly the user
2654 specified size. */
2655 if (value_->has_len()) {
2656 NetNet*net = new NetNet(scope, scope->local_symbol(),
2657 NetNet::IMPLICIT, value_->len());
2658 net->data_type(IVL_VT_LOGIC);
2659 net->local_flag(true);
2660 net->set_signed(value_->has_sign());
2661 NetConst*tmp = new NetConst(scope, scope->local_symbol(),
2662 *value_);
2663 connect(net->pin(0), tmp->pin(0));
2665 des->add_node(tmp);
2666 return net;
2669 /* None of the above tight constraints are present, so make a
2670 plausible choice for the width. Try to reduce the width as
2671 much as possible by eliminating high zeros of unsigned
2672 numbers. */
2674 if (must_be_self_determined_flag) {
2675 cerr << get_line() << ": error: No idea how wide to make "
2676 << "the unsized constant " << *value_ << "." << endl;
2677 des->errors += 1;
2680 unsigned width = value_->len();
2682 if (value_->has_sign() && (value_->get(width-1) == verinum::V0)) {
2684 /* If the number is signed, but known to be positive,
2685 then reduce it down as if it were unsigned. */
2686 while (width > 1) {
2687 if (value_->get(width-1) != verinum::V0)
2688 break;
2689 width -= 1;
2692 } else if (value_->has_sign() == false) {
2693 while ( (width > 1) && (value_->get(width-1) == verinum::V0))
2694 width -= 1;
2697 verinum num (verinum::V0, width);
2698 for (unsigned idx = 0 ; idx < width ; idx += 1)
2699 num.set(idx, value_->get(idx));
2701 NetNet*net = new NetNet(scope, scope->local_symbol(),
2702 NetNet::IMPLICIT, width);
2703 net->data_type(IVL_VT_LOGIC);
2704 net->local_flag(true);
2705 NetConst*tmp = new NetConst(scope, scope->local_symbol(), num);
2706 connect(net->pin(0), tmp->pin(0));
2708 des->add_node(tmp);
2709 return net;
2713 * A string is a NetEConst node that is made of the ASCII bits of the
2714 * string instead of the bits of a number. In fact, a string is just
2715 * another numeric notation.
2717 NetNet* PEString::elaborate_net(Design*des, NetScope*scope,
2718 unsigned lwidth,
2719 const NetExpr* rise,
2720 const NetExpr* fall,
2721 const NetExpr* decay,
2722 Link::strength_t drive0,
2723 Link::strength_t drive1) const
2725 unsigned strbits = strlen(text_) * 8;
2726 NetNet*net;
2728 /* If we are constrained by a l-value size, then just make a
2729 number constant with the correct size and set as many bits
2730 in that constant as make sense. Pad excess with zeros. */
2731 if (lwidth > 0) {
2732 net = new NetNet(scope, scope->local_symbol(),
2733 NetNet::IMPLICIT, lwidth);
2735 } else {
2736 net = new NetNet(scope, scope->local_symbol(),
2737 NetNet::IMPLICIT, strbits);
2739 net->data_type(IVL_VT_BOOL);
2740 net->local_flag(true);
2742 /* Make a verinum that is filled with the 0 pad. */
2743 verinum num(verinum::V0, net->vector_width());
2745 unsigned idx;
2746 for (idx = 0 ; idx < num.len() && idx < strbits; idx += 1) {
2747 char byte = text_[strbits/8 - 1 - idx/8];
2748 char mask = 1<<(idx%8);
2749 num.set(idx, (byte & mask)? verinum::V1 : verinum::V0);
2752 NetConst*tmp = new NetConst(scope, scope->local_symbol(), num);
2753 tmp->set_line(*this);
2754 des->add_node(tmp);
2756 connect(net->pin(0), tmp->pin(0));
2758 return net;
2762 * Elaborate the ternary operator in a netlist by creating a LPM_MUX
2763 * with width matching the result, size == 2 and 1 select input. These
2764 * expressions come from code like:
2766 * res = test ? a : b;
2768 * The res has the width requested of this method, and the a and b
2769 * expressions have their own similar widths. The test expression is
2770 * only a single bit wide. The output from this function is a NetNet
2771 * object the width of the <res> expression and connected to the
2772 * Result pins of the LPM_MUX device. Any width not covered by the
2773 * width of the mux is padded with a NetConst device.
2775 NetNet* PETernary::elaborate_net(Design*des, NetScope*scope,
2776 unsigned width,
2777 const NetExpr* rise,
2778 const NetExpr* fall,
2779 const NetExpr* decay,
2780 Link::strength_t drive0,
2781 Link::strength_t drive1) const
2783 NetNet* expr_sig = expr_->elaborate_net(des, scope, 0, 0, 0, 0);
2784 NetNet* tru_sig = tru_->elaborate_net(des, scope, width, 0, 0, 0);
2785 NetNet* fal_sig = fal_->elaborate_net(des, scope, width, 0, 0, 0);
2786 if (expr_sig == 0 || tru_sig == 0 || fal_sig == 0) {
2787 des->errors += 1;
2788 return 0;
2791 /* The type of the true and false expressions must
2792 match. These become the type of the resulting
2793 expression. */
2795 ivl_variable_type_t expr_type = tru_sig->data_type();
2797 if (tru_sig->data_type() != fal_sig->data_type()) {
2798 cerr << get_line() << ": error: True and False clauses of"
2799 << " ternary expression have differnt types." << endl;
2800 cerr << get_line() << ": : True clause is "
2801 << tru_sig->data_type() << ", false clause is "
2802 << fal_sig->data_type() << "." << endl;
2804 des->errors += 1;
2805 expr_type = IVL_VT_NO_TYPE;
2807 } else if (expr_type == IVL_VT_NO_TYPE) {
2808 cerr << get_line() << ": internal error: True and false "
2809 << "clauses of ternary both have NO TYPE." << endl;
2810 des->errors += 1;
2813 /* The natural width of the expression is the width of the
2814 largest condition. Normally they should be the same size,
2815 but if we do not get a size from the context, or the
2816 expressions resist, we need to cope. */
2817 unsigned iwidth = tru_sig->vector_width();
2818 if (fal_sig->vector_width() > iwidth)
2819 iwidth = fal_sig->vector_width();
2822 /* If the width is not passed from the context, then take the
2823 widest result as our width. */
2824 if (width == 0)
2825 width = iwidth;
2827 /* If the expression has width, then generate a boolean result
2828 by connecting an OR gate to calculate the truth value of
2829 the result. In the end, the result needs to be a single bit. */
2830 if (expr_sig->vector_width() > 1) {
2831 NetUReduce*log = new NetUReduce(scope, scope->local_symbol(),
2832 NetUReduce::OR,
2833 expr_sig->vector_width());
2834 log->set_line(*this);
2835 des->add_node(log);
2836 connect(log->pin(1), expr_sig->pin(0));
2838 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
2839 NetNet::IMPLICIT, 1);
2840 tmp->data_type(IVL_VT_LOGIC);
2841 tmp->local_flag(true);
2842 connect(log->pin(0), tmp->pin(0));
2844 expr_sig = tmp;
2847 assert(expr_sig->vector_width() == 1);
2849 /* This is the width of the LPM_MUX device that I'm about to
2850 create. It may be smaller then the desired output, but I'll
2851 handle padding below. Note that in principle the
2852 alternatives should be padded to the output width first,
2853 but it is more efficient to pad them only just enough to
2854 prevent loss, and do the finished padding later.
2856 Create a NetNet object wide enough to hold the
2857 result. Also, pad the result values (if necessary) so that
2858 the mux inputs can be fully connected. */
2860 unsigned dwidth = (iwidth > width)? width : iwidth;
2862 NetNet*sig = new NetNet(scope, scope->local_symbol(),
2863 NetNet::WIRE, dwidth);
2864 sig->data_type(expr_type);
2865 sig->local_flag(true);
2867 if (fal_sig->vector_width() < dwidth)
2868 fal_sig = pad_to_width(des, fal_sig, dwidth);
2870 if (tru_sig->vector_width() < dwidth)
2871 tru_sig = pad_to_width(des, tru_sig, dwidth);
2873 if (dwidth < fal_sig->vector_width())
2874 fal_sig = crop_to_width(des, fal_sig, dwidth);
2876 if (dwidth < tru_sig->vector_width())
2877 tru_sig = crop_to_width(des, tru_sig, dwidth);
2879 /* Make the device and connect its outputs to the osig and
2880 inputs to the tru and false case nets. Also connect the
2881 selector bit to the sel input.
2883 The inputs are the 0 (false) connected to fal_sig and 1
2884 (true) connected to tru_sig. */
2886 NetMux*mux = new NetMux(scope, scope->local_symbol(), dwidth, 2, 1);
2887 connect(mux->pin_Sel(), expr_sig->pin(0));
2889 /* Connect the data inputs. */
2890 connect(mux->pin_Data(0), fal_sig->pin(0));
2891 connect(mux->pin_Data(1), tru_sig->pin(0));
2893 /* If there are non-zero output delays, then create bufz
2894 devices to carry the propagation delays. Otherwise, just
2895 connect the result to the output. */
2896 if (rise || fall || decay) {
2897 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
2898 NetNet::WIRE, dwidth);
2899 tmp->data_type(expr_type);
2900 tmp->local_flag(true);
2902 NetBUFZ*tmpz = new NetBUFZ(scope, scope->local_symbol(), dwidth);
2903 tmpz->rise_time(rise);
2904 tmpz->fall_time(fall);
2905 tmpz->decay_time(decay);
2906 tmpz->pin(0).drive0(drive0);
2907 tmpz->pin(0).drive1(drive1);
2909 connect(mux->pin_Result(), tmp->pin(0));
2910 connect(tmp->pin(0), tmpz->pin(1));
2911 connect(sig->pin(0), tmpz->pin(0));
2913 des->add_node(tmpz);
2915 } else {
2916 connect(mux->pin_Result(), sig->pin(0));
2919 /* If the MUX device result is too narrow to fill out the
2920 desired result, pad with zeros... */
2921 assert(dwidth <= width);
2923 des->add_node(mux);
2925 /* If the MUX device results is too narrow to fill out the
2926 desired result, then pad it. It is OK to have a too-narrow
2927 result here because the dwidth choice is >= the width of
2928 both alternatives. Thus, padding here is equivalent to
2929 padding inside, and is cheaper. */
2930 if (dwidth < width)
2931 sig = pad_to_width(des, sig, width);
2933 return sig;
2936 NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
2937 unsigned width,
2938 const NetExpr* rise,
2939 const NetExpr* fall,
2940 const NetExpr* decay,
2941 Link::strength_t drive0,
2942 Link::strength_t drive1) const
2945 // Some unary operands allow the operand to be
2946 // self-determined, and some do not.
2947 unsigned owidth = 0;
2948 switch (op_) {
2949 case '~':
2950 case '-':
2951 owidth = width;
2952 break;
2955 NetNet* sig = 0;
2956 NetLogic*gate;
2959 // Handle the special case of a 2's complement of a constant
2960 // value. This can be reduced to a no-op on a precalculated
2961 // result.
2962 if (op_ == '-') do {
2963 // TODO: Should replace this with a call to
2964 // elab_and_eval. Possibly blend this with the rest of
2965 // the elaboration as well.
2966 verinum*val = expr_->eval_const(des, scope);
2967 if (val == 0)
2968 break;
2970 if (width == 0)
2971 width = val->len();
2973 assert(width > 0);
2974 sig = new NetNet(scope, scope->local_symbol(),
2975 NetNet::WIRE, width);
2976 sig->data_type(IVL_VT_LOGIC);
2977 sig->local_flag(true);
2979 /* Take the 2s complement by taking the 1s complement
2980 and adding 1. */
2981 verinum tmp (v_not(*val), width);
2982 verinum one (1UL, width);
2983 tmp = verinum(tmp + one, width);
2984 tmp.has_sign(val->has_sign());
2986 NetConst*con = new NetConst(scope, scope->local_symbol(), tmp);
2987 connect(sig->pin(0), con->pin(0));
2989 if (debug_elaborate) {
2990 cerr << get_line() << ": debug: Replace expression "
2991 << *this << " with constant " << tmp << "."<<endl;
2994 delete val;
2995 des->add_node(con);
2996 return sig;
2998 } while (0);
3000 NetNet* sub_sig = expr_->elaborate_net(des, scope, owidth, 0, 0, 0);
3001 if (sub_sig == 0) {
3002 des->errors += 1;
3003 return 0;
3005 assert(sub_sig);
3007 bool reduction=false;
3008 NetUReduce::TYPE rtype = NetUReduce::NONE;
3010 switch (op_) {
3011 case '~': // Bitwise NOT
3012 sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE,
3013 sub_sig->vector_width());
3014 sig->data_type(sub_sig->data_type());
3015 sig->local_flag(true);
3016 gate = new NetLogic(scope, scope->local_symbol(),
3017 2, NetLogic::NOT, sub_sig->vector_width());
3018 gate->set_line(*this);
3019 des->add_node(gate);
3020 gate->rise_time(rise);
3021 gate->fall_time(fall);
3022 gate->decay_time(decay);
3024 connect(gate->pin(1), sub_sig->pin(0));
3025 connect(gate->pin(0), sig->pin(0));
3026 break;
3028 case 'N': // Reduction NOR
3029 case '!': // Reduction NOT
3030 reduction=true; rtype = NetUReduce::NOR; break;
3031 case '&': // Reduction AND
3032 reduction=true; rtype = NetUReduce::AND; break;
3033 case '|': // Reduction OR
3034 reduction=true; rtype = NetUReduce::OR; break;
3035 case '^': // Reduction XOR
3036 reduction=true; rtype = NetUReduce::XOR; break;
3037 case 'A': // Reduction NAND (~&)
3038 reduction=true; rtype = NetUReduce::NAND; break;
3039 case 'X': // Reduction XNOR (~^)
3040 reduction=true; rtype = NetUReduce::XNOR; break;
3042 case '-': // Unary 2's complement.
3043 // If this expression is self determined, get its width
3044 // from the sub_expression.
3045 if (owidth == 0)
3046 owidth = sub_sig->vector_width();
3048 sig = new NetNet(scope, scope->local_symbol(),
3049 NetNet::WIRE, owidth);
3050 sig->data_type(sub_sig->data_type());
3051 sig->local_flag(true);
3053 if (sub_sig->vector_width() < owidth)
3054 sub_sig = pad_to_width(des, sub_sig, owidth);
3056 switch (sub_sig->vector_width()) {
3057 case 0:
3058 assert(0);
3059 break;
3061 case 1:
3062 gate = new NetLogic(scope, scope->local_symbol(),
3063 2, NetLogic::BUF, 1);
3064 connect(gate->pin(0), sig->pin(0));
3065 connect(gate->pin(1), sub_sig->pin(0));
3066 des->add_node(gate);
3067 gate->rise_time(rise);
3068 gate->fall_time(fall);
3069 gate->decay_time(decay);
3070 break;
3072 default:
3073 NetAddSub*sub = new NetAddSub(scope, scope->local_symbol(),
3074 sig->vector_width());
3075 sub->attribute(perm_string::literal("LPM_Direction"),
3076 verinum("SUB"));
3078 des->add_node(sub);
3080 connect(sig->pin(0), sub->pin_Result());
3081 connect(sub_sig->pin(0), sub->pin_DataB());
3083 verinum tmp_num (verinum::V0, sub->width(), true);
3084 NetConst*tmp_con = new NetConst(scope,
3085 scope->local_symbol(),
3086 tmp_num);
3087 des->add_node(tmp_con);
3089 NetNet*tmp_sig = new NetNet(scope, scope->local_symbol(),
3090 NetNet::WIRE,
3091 sub_sig->vector_width());
3092 tmp_sig->data_type(sub_sig->data_type());
3093 tmp_sig->local_flag(true);
3095 connect(tmp_sig->pin(0), sub->pin_DataA());
3096 connect(tmp_sig->pin(0), tmp_con->pin(0));
3097 break;
3099 break;
3101 default:
3102 cerr << "internal error: Unhandled UNARY '" << op_ << "'" << endl;
3103 sig = 0;
3106 if (reduction) {
3107 NetUReduce*rgate;
3109 // The output of a reduction operator is 1 bit
3110 sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, 1);
3111 sig->data_type(sub_sig->data_type());
3112 sig->local_flag(true);
3114 rgate = new NetUReduce(scope, scope->local_symbol(),
3115 rtype, sub_sig->vector_width());
3116 rgate->set_line(*this);
3117 connect(rgate->pin(0), sig->pin(0));
3118 connect(rgate->pin(1), sub_sig->pin(0));
3120 des->add_node(rgate);
3121 rgate->rise_time(rise);
3122 rgate->fall_time(fall);
3123 rgate->decay_time(decay);
3126 return sig;
3130 * $Log: elab_net.cc,v $
3131 * Revision 1.207 2007/06/12 04:05:45 steve
3132 * Put instantiated modules in the proper generated scope.
3134 * Revision 1.206 2007/06/04 02:19:07 steve
3135 * Handle bit/part select of array words in nets.
3137 * Revision 1.205 2007/06/02 03:42:12 steve
3138 * Properly evaluate scope path expressions.
3140 * Revision 1.204 2007/05/24 04:07:11 steve
3141 * Rework the heirarchical identifier parse syntax and pform
3142 * to handle more general combinations of heirarch and bit selects.
3144 * Revision 1.203 2007/04/18 01:40:49 steve
3145 * Fix elaboration of multiply of two constants.
3147 * Revision 1.202 2007/04/17 04:18:10 steve
3148 * Support part select of array words in net contexts.
3150 * Revision 1.201 2007/03/22 16:08:14 steve
3151 * Spelling fixes from Larry
3153 * Revision 1.200 2007/02/27 06:10:16 steve
3154 * Better error message around repeat concatenation syntax.
3156 * Revision 1.199 2007/02/26 19:49:48 steve
3157 * Spelling fixes (larry doolittle)
3159 * Revision 1.198 2007/02/05 01:42:31 steve
3160 * Set some missing local flags.
3162 * Revision 1.197 2007/02/01 19:06:06 steve
3163 * Ternary output node is local.
3165 * Revision 1.196 2007/02/01 03:14:33 steve
3166 * Detect and report arrays without index in net contexts.
3168 * Revision 1.195 2007/01/31 04:21:10 steve
3169 * Add method to bind assertions to verilog source lines.
3171 * Revision 1.194 2007/01/20 02:10:45 steve
3172 * Get argument widths right for shift results.
3174 * Revision 1.193 2007/01/19 04:26:24 steve
3175 * Fix missing data_type mark for array words.
3177 * Revision 1.192 2007/01/16 05:44:15 steve
3178 * Major rework of array handling. Memories are replaced with the
3179 * more general concept of arrays. The NetMemory and NetEMemory
3180 * classes are removed from the ivl core program, and the IVL_LPM_RAM
3181 * lpm type is removed from the ivl_target API.
3183 * Revision 1.191 2006/12/08 03:43:26 steve
3184 * Prevent name clash when processing parameter in net.
3186 * Revision 1.190 2006/11/26 06:29:16 steve
3187 * Fix nexus widths for direct link assign and ternary nets.
3189 * Revision 1.189 2006/08/08 05:11:37 steve
3190 * Handle 64bit delay constants.
3192 * Revision 1.188 2006/06/20 05:06:47 steve
3193 * Sign extend operands of signed addition.
3195 * Revision 1.187 2006/06/18 04:15:50 steve
3196 * Add support for system functions in continuous assignments.
3198 * Revision 1.186 2006/06/02 04:48:50 steve
3199 * Make elaborate_expr methods aware of the width that the context
3200 * requires of it. In the process, fix sizing of the width of unary
3201 * minus is context determined sizes.
3203 * Revision 1.185 2006/05/19 04:44:55 steve
3204 * Get self-determined unary - width right.
3206 * Revision 1.184 2006/05/01 20:47:58 steve
3207 * More explicit datatype setup.
3209 * Revision 1.183 2006/04/30 05:17:48 steve
3210 * Get the data type of part select results right.
3212 * Revision 1.182 2006/04/28 05:09:51 steve
3213 * Handle padding of MUX net results.
3215 * Revision 1.181 2006/04/28 04:28:35 steve
3216 * Allow concatenations as arguments to inout ports.
3218 * Revision 1.180 2006/04/24 05:15:07 steve
3219 * Fix support for indexed part select in continuous assign l-values.
3221 * Revision 1.179 2006/04/10 00:32:14 steve
3222 * Clean up index expression error message.
3224 * Revision 1.178 2006/02/02 02:43:57 steve
3225 * Allow part selects of memory words in l-values.
3227 * Revision 1.177 2006/01/02 05:33:19 steve
3228 * Node delays can be more general expressions in structural contexts.
3230 * Revision 1.176 2005/10/11 16:15:52 steve
3231 * Logical or/and return VT_LOGIC type.
3233 * Revision 1.175 2005/09/19 15:21:09 steve
3234 * Fix data type of parameters to logic.
3236 * Revision 1.174 2005/09/15 23:04:09 steve
3237 * Make sure div, mod and mult nodes have line number info.
3239 * Revision 1.173 2005/09/14 15:15:44 steve
3240 * fit type elaboration of logical not.
3242 * Revision 1.172 2005/09/01 04:10:47 steve
3243 * Check operand types for compatibility.
3245 * Revision 1.171 2005/08/31 05:07:31 steve
3246 * Handle memory references is continuous assignments.
3248 * Revision 1.170 2005/08/06 17:58:16 steve
3249 * Implement bi-directional part selects.
3251 * Revision 1.169 2005/07/15 04:13:25 steve
3252 * Match data type of PV select input/output.
3254 * Revision 1.168 2005/07/15 00:42:02 steve
3255 * Get output type correct for binary mux (ternary) expression.
3257 * Revision 1.167 2005/07/11 16:56:50 steve
3258 * Remove NetVariable and ivl_variable_t structures.
3260 * Revision 1.166 2005/07/07 16:22:49 steve
3261 * Generalize signals to carry types.
3263 * Revision 1.165 2005/05/24 01:44:27 steve
3264 * Do sign extension of structuran nets.
3266 * Revision 1.164 2005/05/19 03:51:38 steve
3267 * Make sure comparison widths match.
3269 * Revision 1.163 2005/05/10 05:10:40 steve
3270 * Make sig-eq-constant optimization more effective.
3272 * Revision 1.162 2005/05/08 23:44:08 steve
3273 * Add support for variable part select.
3275 * Revision 1.161 2005/05/06 00:25:13 steve
3276 * Handle synthesis of concatenation expressions.
3278 * Revision 1.160 2005/04/08 04:52:31 steve
3279 * Make clear that memory addresses are cannonical.
3281 * Revision 1.159 2005/04/06 05:29:08 steve
3282 * Rework NetRamDq and IVL_LPM_RAM nodes.
3284 * Revision 1.158 2005/03/19 06:59:53 steve
3285 * Handle wide operands to logical AND.
3287 * Revision 1.157 2005/03/19 06:23:49 steve
3288 * Handle LPM shifts.
3290 * Revision 1.156 2005/03/18 02:56:03 steve
3291 * Add support for LPM_UFUNC user defined functions.
3293 * Revision 1.155 2005/03/13 01:26:48 steve
3294 * UPdate elabrate continuous assighn of string to net.
3296 * Revision 1.154 2005/03/12 06:43:35 steve
3297 * Update support for LPM_MOD.
3299 * Revision 1.153 2005/03/09 05:52:03 steve
3300 * Handle case inequality in netlists.
3302 * Revision 1.152 2005/02/19 02:43:38 steve
3303 * Support shifts and divide.
3305 * Revision 1.151 2005/02/12 06:25:40 steve
3306 * Restructure NetMux devices to pass vectors.
3307 * Generate NetMux devices from ternary expressions,
3308 * Reduce NetMux devices to bufif when appropriate.
3310 * Revision 1.150 2005/02/03 04:56:20 steve
3311 * laborate reduction gates into LPM_RED_ nodes.
3313 * Revision 1.149 2005/01/30 05:20:38 steve
3314 * Elaborate unary subtract and NOT in netlist
3315 * contexts, and concatenation too.
3317 * Revision 1.148 2005/01/29 18:46:18 steve
3318 * Netlist boolean expressions generate gate vectors.
3320 * Revision 1.147 2005/01/29 16:46:22 steve
3321 * Elaborate parameter reference to desired width without concats.
3323 * Revision 1.146 2005/01/29 00:37:06 steve
3324 * Integrate pr1072 fix from v0_8-branch.
3326 * Revision 1.145 2005/01/28 05:39:33 steve
3327 * Simplified NetMult and IVL_LPM_MULT.
3329 * Revision 1.144 2005/01/22 18:16:00 steve
3330 * Remove obsolete NetSubnet class.
3332 * Revision 1.143 2005/01/22 01:06:55 steve
3333 * Change case compare from logic to an LPM node.
3335 * Revision 1.142 2005/01/16 04:20:32 steve
3336 * Implement LPM_COMPARE nodes as two-input vector functors.
3338 * Revision 1.141 2005/01/13 00:23:10 steve
3339 * Fix elaboration of == compared to constants.
3341 * Revision 1.140 2005/01/09 20:16:00 steve
3342 * Use PartSelect/PV and VP to handle part selects through ports.
3344 * Revision 1.139 2004/12/11 02:31:25 steve
3345 * Rework of internals to carry vectors through nexus instead
3346 * of single bits. Make the ivl, tgt-vvp and vvp initial changes
3347 * down this path.
3349 * Revision 1.138 2004/10/04 03:09:38 steve
3350 * Fix excessive error message.
3352 * Revision 1.137 2004/10/04 01:10:52 steve
3353 * Clean up spurious trailing white space.
3355 * Revision 1.136 2004/10/04 00:25:46 steve
3356 * Error message to match assertion.