Make %t with real values use specified width if given.
[iverilog.git] / expr_synth.cc
blobed2c0a3c3007e403251c72738f0fe08706709c9e
1 /*
2 * Copyright (c) 1999-2005 Stephen Williams (steve@icarus.com)
4 * This source code is free software; you can redistribute it
5 * and/or modify it in source code form under the terms of the GNU
6 * General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option)
8 * any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 #ifdef HAVE_CVS_IDENT
20 #ident "$Id: expr_synth.cc,v 1.87 2007/06/02 03:42:12 steve Exp $"
21 #endif
23 # include "config.h"
25 # include <iostream>
27 # include "netlist.h"
28 # include "netmisc.h"
29 # include "ivl_assert.h"
31 NetNet* NetExpr::synthesize(Design*des)
33 cerr << get_line() << ": internal error: cannot synthesize expression: "
34 << *this << endl;
35 des->errors += 1;
36 return 0;
40 * Make an LPM_ADD_SUB device from addition operators.
42 NetNet* NetEBAdd::synthesize(Design*des)
44 assert((op()=='+') || (op()=='-'));
46 NetNet*lsig = left_->synthesize(des);
47 NetNet*rsig = right_->synthesize(des);
49 assert(expr_width() >= lsig->vector_width());
50 assert(expr_width() >= rsig->vector_width());
52 lsig = pad_to_width(des, lsig, expr_width());
53 rsig = pad_to_width(des, rsig, expr_width());
55 assert(lsig->vector_width() == rsig->vector_width());
56 unsigned width=lsig->vector_width();
58 perm_string path = lsig->scope()->local_symbol();
59 NetNet*osig = new NetNet(lsig->scope(), path, NetNet::IMPLICIT, width);
60 osig->local_flag(true);
61 osig->data_type(expr_type());
63 perm_string oname = osig->scope()->local_symbol();
64 NetAddSub *adder = new NetAddSub(lsig->scope(), oname, width);
65 connect(lsig->pin(0), adder->pin_DataA());
66 connect(rsig->pin(0), adder->pin_DataB());
67 connect(osig->pin(0), adder->pin_Result());
68 des->add_node(adder);
70 switch (op()) {
71 case '+':
72 adder->attribute(perm_string::literal("LPM_Direction"), verinum("ADD"));
73 break;
74 case '-':
75 adder->attribute(perm_string::literal("LPM_Direction"), verinum("SUB"));
76 break;
79 return osig;
83 * The bitwise logic operators are turned into discrete gates pretty
84 * easily. Synthesize the left and right sub-expressions to get
85 * signals, then just connect a single gate to each bit of the vector
86 * of the expression.
88 NetNet* NetEBBits::synthesize(Design*des)
90 NetNet*lsig = left_->synthesize(des);
91 NetNet*rsig = right_->synthesize(des);
93 NetScope*scope = lsig->scope();
94 assert(scope);
96 if (lsig->vector_width() != rsig->vector_width()) {
97 cerr << get_line() << ": internal error: bitwise (" << op_
98 << ") widths do not match: " << lsig->vector_width()
99 << " != " << rsig->vector_width() << endl;
100 cerr << get_line() << ": : width="
101 << lsig->vector_width() << ": " << *left_ << endl;
102 cerr << get_line() << ": : width="
103 << rsig->vector_width() << ": " << *right_ << endl;
104 return 0;
107 assert(lsig->vector_width() == rsig->vector_width());
108 NetNet*osig = new NetNet(scope, scope->local_symbol(),
109 NetNet::IMPLICIT, lsig->vector_width());
110 osig->local_flag(true);
111 osig->data_type(expr_type());
113 perm_string oname = scope->local_symbol();
114 unsigned wid = lsig->vector_width();
115 NetLogic*gate;
117 switch (op()) {
118 case '&':
119 gate = new NetLogic(scope, oname, 3, NetLogic::AND, wid);
120 break;
121 case '|':
122 gate = new NetLogic(scope, oname, 3, NetLogic::OR, wid);
123 break;
124 case '^':
125 gate = new NetLogic(scope, oname, 3, NetLogic::XOR, wid);
126 break;
127 case 'O':
128 gate = new NetLogic(scope, oname, 3, NetLogic::NOR, wid);
129 break;
130 case 'X':
131 gate = new NetLogic(scope, oname, 3, NetLogic::XNOR, wid);
132 break;
133 default:
134 assert(0);
137 connect(osig->pin(0), gate->pin(0));
138 connect(lsig->pin(0), gate->pin(1));
139 connect(rsig->pin(0), gate->pin(2));
141 gate->set_line(*this);
142 des->add_node(gate);
144 return osig;
147 NetNet* NetEBComp::synthesize(Design*des)
150 NetNet*lsig = left_->synthesize(des);
151 NetNet*rsig = right_->synthesize(des);
153 NetScope*scope = lsig->scope();
154 assert(scope);
156 unsigned width = lsig->vector_width();
157 if (rsig->vector_width() > width)
158 width = rsig->vector_width();
160 lsig = pad_to_width(des, lsig, width);
161 rsig = pad_to_width(des, rsig, width);
163 NetNet*osig = new NetNet(scope, scope->local_symbol(),
164 NetNet::IMPLICIT, 1);
165 osig->set_line(*this);
166 osig->local_flag(true);
167 osig->data_type(IVL_VT_LOGIC);
169 /* Handle the special case of a single bit equality
170 operation. Make an XNOR gate instead of a comparator. */
171 if ((width == 1) && ((op_ == 'e') || (op_ == 'E'))) {
172 NetLogic*gate = new NetLogic(scope, scope->local_symbol(),
173 3, NetLogic::XNOR, 1);
174 gate->set_line(*this);
175 connect(gate->pin(0), osig->pin(0));
176 connect(gate->pin(1), lsig->pin(0));
177 connect(gate->pin(2), rsig->pin(0));
178 des->add_node(gate);
179 return osig;
182 /* Handle the special case of a single bit inequality
183 operation. This is similar to single bit equality, but uses
184 an XOR instead of an XNOR gate. */
185 if ((width == 1) && ((op_ == 'n') || (op_ == 'N'))) {
186 NetLogic*gate = new NetLogic(scope, scope->local_symbol(),
187 3, NetLogic::XOR, 1);
188 gate->set_line(*this);
189 connect(gate->pin(0), osig->pin(0));
190 connect(gate->pin(1), lsig->pin(0));
191 connect(gate->pin(2), rsig->pin(0));
192 des->add_node(gate);
193 return osig;
197 NetCompare*dev = new NetCompare(scope, scope->local_symbol(), width);
198 dev->set_line(*this);
199 des->add_node(dev);
201 connect(dev->pin_DataA(), lsig->pin(0));
202 connect(dev->pin_DataB(), rsig->pin(0));
205 switch (op_) {
206 case '<':
207 connect(dev->pin_ALB(), osig->pin(0));
208 break;
209 case '>':
210 connect(dev->pin_AGB(), osig->pin(0));
211 break;
212 case 'e': // ==
213 case 'E': // === ?
214 connect(dev->pin_AEB(), osig->pin(0));
215 break;
216 case 'G': // >=
217 connect(dev->pin_AGEB(), osig->pin(0));
218 break;
219 case 'L': // <=
220 connect(dev->pin_ALEB(), osig->pin(0));
221 break;
222 case 'n': // !=
223 case 'N': // !==
224 connect(dev->pin_ANEB(), osig->pin(0));
225 break;
227 default:
228 cerr << get_line() << ": internal error: cannot synthesize "
229 "comparison: " << *this << endl;
230 des->errors += 1;
231 return 0;
234 return osig;
237 NetNet* NetEBPow::synthesize(Design*des)
239 cerr << get_line() << ": internal error: Do not yet know how to handle"
240 << " power operator in this context." << endl;
241 des->errors += 1;
242 return 0;
245 NetNet* NetEBMult::synthesize(Design*des)
247 NetNet*lsig = left_->synthesize(des);
248 NetNet*rsig = right_->synthesize(des);
250 if (lsig == 0)
251 return 0;
253 if (rsig == 0)
254 return 0;
256 NetScope*scope = lsig->scope();
257 assert(scope);
259 NetMult*mult = new NetMult(scope, scope->local_symbol(),
260 expr_width(),
261 lsig->vector_width(),
262 rsig->vector_width());
263 des->add_node(mult);
265 mult->set_signed( has_sign() );
266 mult->set_line(*this);
268 connect(mult->pin_DataA(), lsig->pin(0));
269 connect(mult->pin_DataB(), rsig->pin(0));
271 NetNet*osig = new NetNet(scope, scope->local_symbol(),
272 NetNet::IMPLICIT, expr_width());
273 osig->data_type(lsig->data_type());
274 osig->set_line(*this);
275 osig->data_type(expr_type());
276 osig->local_flag(true);
278 connect(mult->pin_Result(), osig->pin(0));
280 return osig;
283 NetNet* NetEBDiv::synthesize(Design*des)
285 NetNet*lsig = left_->synthesize(des);
286 NetNet*rsig = right_->synthesize(des);
288 NetScope*scope = lsig->scope();
290 NetNet*osig = new NetNet(scope, scope->local_symbol(),
291 NetNet::IMPLICIT, expr_width());
292 osig->set_line(*this);
293 osig->data_type(lsig->data_type());
294 osig->local_flag(true);
296 switch (op()) {
298 case '/': {
299 NetDivide*div = new NetDivide(scope, scope->local_symbol(),
300 expr_width(),
301 lsig->vector_width(),
302 rsig->vector_width());
303 div->set_line(*this);
304 des->add_node(div);
306 connect(div->pin_DataA(), lsig->pin(0));
307 connect(div->pin_DataB(), rsig->pin(0));
308 connect(div->pin_Result(),osig->pin(0));
309 break;
312 case '%': {
313 NetModulo*div = new NetModulo(scope, scope->local_symbol(),
314 expr_width(),
315 lsig->vector_width(),
316 rsig->vector_width());
317 div->set_line(*this);
318 des->add_node(div);
320 connect(div->pin_DataA(), lsig->pin(0));
321 connect(div->pin_DataB(), rsig->pin(0));
322 connect(div->pin_Result(),osig->pin(0));
323 break;
326 default: {
327 cerr << get_line() << ": internal error: "
328 << "NetEBDiv has unexpeced op() code: "
329 << op() << endl;
330 des->errors += 1;
332 delete osig;
333 return 0;
337 return osig;
340 NetNet* NetEBLogic::synthesize(Design*des)
342 NetNet*lsig = left_->synthesize(des);
343 NetNet*rsig = right_->synthesize(des);
345 if (lsig == 0)
346 return 0;
348 if (rsig == 0)
349 return 0;
351 NetScope*scope = lsig->scope();
352 assert(scope);
354 NetNet*osig = new NetNet(scope, scope->local_symbol(),
355 NetNet::IMPLICIT, 1);
356 osig->data_type(expr_type());
357 osig->local_flag(true);
360 if (op() == 'o') {
362 /* Logic OR can handle the reduction *and* the logical
363 comparison with a single wide OR gate. So handle this
364 magically. */
366 perm_string oname = scope->local_symbol();
368 NetLogic*olog = new NetLogic(scope, oname,
369 lsig->pin_count()+rsig->pin_count()+1,
370 NetLogic::OR, 1);
372 connect(osig->pin(0), olog->pin(0));
374 unsigned pin = 1;
375 for (unsigned idx = 0 ; idx < lsig->pin_count() ; idx = 1)
376 connect(olog->pin(pin+idx), lsig->pin(idx));
378 pin += lsig->pin_count();
379 for (unsigned idx = 0 ; idx < rsig->pin_count() ; idx = 1)
380 connect(olog->pin(pin+idx), rsig->pin(idx));
382 des->add_node(olog);
384 } else {
385 assert(op() == 'a');
387 /* Create the logic AND gate. This is a single bit
388 output, with inputs for each of the operands. */
389 NetLogic*olog;
390 perm_string oname = scope->local_symbol();
392 olog = new NetLogic(scope, oname, 3, NetLogic::AND, 1);
394 connect(osig->pin(0), olog->pin(0));
395 des->add_node(olog);
397 /* XXXX Here, I need to reduce the parameters with
398 reduction or. */
401 /* By this point, the left and right parameters have been
402 reduced to single bit values. Now we just connect them to
403 the logic gate. */
404 assert(lsig->pin_count() == 1);
405 connect(lsig->pin(0), olog->pin(1));
407 assert(rsig->pin_count() == 1);
408 connect(rsig->pin(0), olog->pin(2));
412 return osig;
415 NetNet* NetEBShift::synthesize(Design*des)
417 if (! dynamic_cast<NetEConst*>(right_)) {
418 NetExpr*tmp = right_->eval_tree();
419 if (tmp) {
420 delete right_;
421 right_ = tmp;
425 NetNet*lsig = left_->synthesize(des);
426 if (lsig == 0)
427 return 0;
429 bool right_flag = op_ == 'r' || op_ == 'R';
430 bool signed_flag = op_ == 'R';
432 NetScope*scope = lsig->scope();
434 /* Detect the special case where the shift amount is
435 constant. Evaluate the shift amount, and simply reconnect
436 the left operand to the output, but shifted. */
437 if (NetEConst*rcon = dynamic_cast<NetEConst*>(right_)) {
438 verinum shift_v = rcon->value();
439 long shift = shift_v.as_long();
441 if (op() == 'r')
442 shift = 0-shift;
444 if (shift == 0)
445 return lsig;
447 NetNet*osig = new NetNet(scope, scope->local_symbol(),
448 NetNet::IMPLICIT, expr_width());
449 osig->data_type(expr_type());
450 osig->local_flag(true);
452 // ushift is the amount of pad created by the shift.
453 unsigned long ushift = shift>=0? shift : -shift;
454 if (ushift > osig->vector_width())
455 ushift = osig->vector_width();
457 // part_width is the bits of the vector that survive the shift.
458 unsigned long part_width = osig->vector_width() - ushift;
460 verinum znum (verinum::V0, ushift, true);
461 NetConst*zcon = new NetConst(scope, scope->local_symbol(),
462 znum);
463 des->add_node(zcon);
465 /* Detect the special case that the shift is the size of
466 the whole expression. Simply connect the pad to the
467 osig and escape. */
468 if (ushift >= osig->vector_width()) {
469 connect(zcon->pin(0), osig->pin(0));
470 return osig;
473 NetNet*zsig = new NetNet(scope, scope->local_symbol(),
474 NetNet::WIRE, znum.len());
475 zsig->data_type(osig->data_type());
476 zsig->local_flag(true);
477 zsig->set_line(*this);
478 connect(zcon->pin(0), zsig->pin(0));
480 /* Create a part select to reduce the width of the lsig
481 to the amount left by the shift. */
482 NetPartSelect*psel = new NetPartSelect(lsig, shift<0? ushift : 0,
483 part_width,
484 NetPartSelect::VP);
485 des->add_node(psel);
487 NetNet*psig = new NetNet(scope, scope->local_symbol(),
488 NetNet::IMPLICIT, part_width);
489 psig->data_type(expr_type());
490 psig->local_flag(true);
491 psig->set_line(*this);
492 connect(psig->pin(0), psel->pin(0));
494 NetConcat*ccat = new NetConcat(scope, scope->local_symbol(),
495 osig->vector_width(), 2);
496 ccat->set_line(*this);
497 des->add_node(ccat);
499 connect(ccat->pin(0), osig->pin(0));
500 if (shift > 0) {
501 // Left shift.
502 connect(ccat->pin(1), zsig->pin(0));
503 connect(ccat->pin(2), psig->pin(0));
504 } else {
505 // Right shift
506 connect(ccat->pin(1), psig->pin(0));
507 connect(ccat->pin(2), zsig->pin(0));
510 return osig;
513 NetNet*rsig = right_->synthesize(des);
514 if (rsig == 0)
515 return 0;
517 NetNet*osig = new NetNet(scope, scope->local_symbol(),
518 NetNet::IMPLICIT, expr_width());
519 osig->data_type(expr_type());
520 osig->local_flag(true);
522 NetCLShift*dev = new NetCLShift(scope, scope->local_symbol(),
523 osig->vector_width(),
524 rsig->vector_width(),
525 right_flag, signed_flag);
526 dev->set_line(*this);
527 des->add_node(dev);
529 connect(dev->pin_Result(), osig->pin(0));
531 assert(lsig->vector_width() == dev->width());
532 connect(dev->pin_Data(), lsig->pin(0));
534 connect(dev->pin_Distance(), rsig->pin(0));
536 return osig;
539 NetNet* NetEConcat::synthesize(Design*des)
541 /* First, synthesize the operands. */
542 NetNet**tmp = new NetNet*[parms_.count()];
543 bool flag = true;
544 for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
545 tmp[idx] = parms_[idx]->synthesize(des);
546 if (tmp[idx] == 0)
547 flag = false;
550 if (flag == false)
551 return 0;
553 assert(tmp[0]);
554 NetScope*scope = tmp[0]->scope();
555 assert(scope);
557 /* Make a NetNet object to carry the output vector. */
558 perm_string path = scope->local_symbol();
559 NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, expr_width());
560 osig->local_flag(true);
561 osig->data_type(tmp[0]->data_type());
563 NetConcat*concat = new NetConcat(scope, scope->local_symbol(),
564 osig->vector_width(), parms_.count());
565 concat->set_line(*this);
566 des->add_node(concat);
567 connect(concat->pin(0), osig->pin(0));
569 for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
570 connect(concat->pin(idx+1), tmp[parms_.count()-idx-1]->pin(0));
573 delete[]tmp;
574 return osig;
577 NetNet* NetEConst::synthesize(Design*des)
579 NetScope*scope = des->find_root_scope();
580 assert(scope);
582 perm_string path = scope->local_symbol();
583 unsigned width=expr_width();
585 NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, width-1,0);
586 osig->local_flag(true);
587 osig->data_type(IVL_VT_LOGIC);
588 osig->set_signed(has_sign());
589 NetConst*con = new NetConst(scope, scope->local_symbol(), value());
590 connect(osig->pin(0), con->pin(0));
592 des->add_node(con);
593 return osig;
597 * Create a NetLiteral object to represent real valued constants.
599 NetNet* NetECReal::synthesize(Design*des)
601 NetScope*scope = des->find_root_scope();
602 assert(scope);
604 perm_string path = scope->local_symbol();
606 NetNet*osig = new NetNet(scope, path, NetNet::WIRE, 1);
607 osig->local_flag(true);
608 osig->data_type(IVL_VT_REAL);
609 osig->set_signed(has_sign());
610 osig->set_line(*this);
612 NetLiteral*con = new NetLiteral(scope, scope->local_symbol(), value_);
613 des->add_node(con);
614 con->set_line(*this);
616 connect(osig->pin(0), con->pin(0));
617 return osig;
621 * The bitwise unary logic operator (there is only one) is turned
622 * into discrete gates just as easily as the binary ones above.
624 NetNet* NetEUBits::synthesize(Design*des)
626 NetNet*isig = expr_->synthesize(des);
628 NetScope*scope = isig->scope();
629 assert(scope);
631 unsigned width = isig->vector_width();
632 NetNet*osig = new NetNet(scope, scope->local_symbol(),
633 NetNet::IMPLICIT, width);
634 osig->data_type(expr_type());
635 osig->local_flag(true);
637 perm_string oname = scope->local_symbol();
638 NetLogic*gate;
640 switch (op()) {
641 case '~':
642 gate = new NetLogic(scope, oname, 2, NetLogic::NOT, width);
643 break;
644 default:
645 assert(0);
648 connect(osig->pin(0), gate->pin(0));
649 connect(isig->pin(0), gate->pin(1));
651 des->add_node(gate);
653 return osig;
656 NetNet* NetEUReduce::synthesize(Design*des)
658 NetNet*isig = expr_->synthesize(des);
660 NetScope*scope = isig->scope();
661 assert(scope);
663 NetNet*osig = new NetNet(scope, scope->local_symbol(),
664 NetNet::IMPLICIT, 1);
665 osig->data_type(expr_type());
666 osig->local_flag(true);
668 NetUReduce::TYPE rtype = NetUReduce::NONE;
670 switch (op()) {
671 case 'N':
672 case '!':
673 rtype = NetUReduce::NOR;
674 break;
675 case '&':
676 rtype = NetUReduce::AND;
677 break;
678 case '|':
679 rtype = NetUReduce::OR;
680 break;
681 case '^':
682 rtype = NetUReduce::XOR;
683 break;
684 case 'A':
685 rtype = NetUReduce::XNOR;
686 break;
687 case 'X':
688 rtype = NetUReduce::XNOR;
689 break;
690 default:
691 cerr << get_line() << ": internal error: "
692 << "Unable to synthesize " << *this << "." << endl;
693 return 0;
696 NetUReduce*gate = new NetUReduce(scope, scope->local_symbol(),
697 rtype, isig->vector_width());
699 des->add_node(gate);
700 connect(gate->pin(0), osig->pin(0));
701 for (unsigned idx = 0 ; idx < isig->pin_count() ; idx += 1)
702 connect(gate->pin(1+idx), isig->pin(idx));
704 return osig;
707 NetNet* NetESelect::synthesize(Design *des)
710 NetNet*sub = expr_->synthesize(des);
711 if (sub == 0)
712 return 0;
714 NetScope*scope = sub->scope();
716 NetNet*off = 0;
718 // This handles the case that the NetESelect exists to do an
719 // actual part/bit select. Generate a NetPartSelect object to
720 // do the work, and replace "sub" with the selected output.
721 if (base_ != 0) {
722 off = base_->synthesize(des);
724 NetPartSelect*sel = new NetPartSelect(sub, off, expr_width());
725 sel->set_line(*this);
726 des->add_node(sel);
728 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
729 NetNet::IMPLICIT, expr_width());
730 tmp->data_type(sub->data_type());
731 tmp->local_flag(true);
732 tmp->set_line(*this);
733 sub = tmp;
734 connect(sub->pin(0), sel->pin(0));
738 // Now look for the case that the NetESelect actually exists
739 // to change the width of the expression. (i.e. to do
740 // padding.) If this was for an actual part select that at
741 // this point the output vector_width is exactly right, and we
742 // are done.
743 if (sub->vector_width() == expr_width())
744 return sub;
746 // The vector_width is not exactly right, so the source is
747 // probably asking for padding. Create nodes to do sign
748 // extension or 0 extension, depending on the has_sign() mode
749 // of the expression.
751 NetNet*net = new NetNet(scope, scope->local_symbol(),
752 NetNet::IMPLICIT, expr_width());
753 net->data_type(expr_type());
754 net->local_flag(true);
755 net->set_line(*this);
756 if (has_sign()) {
757 NetSignExtend*pad = new NetSignExtend(scope,
758 scope->local_symbol(),
759 expr_width());
760 pad->set_line(*this);
761 des->add_node(pad);
763 connect(pad->pin(1), sub->pin(0));
764 connect(pad->pin(0), net->pin(0));
766 } else {
768 NetConcat*cat = new NetConcat(scope, scope->local_symbol(),
769 expr_width(), 2);
770 cat->set_line(*this);
771 des->add_node(cat);
773 assert(expr_width() > sub->vector_width());
774 unsigned pad_width = expr_width() - sub->vector_width();
775 verinum pad((uint64_t)0, pad_width);
776 NetConst*con = new NetConst(scope, scope->local_symbol(),
777 pad);
778 con->set_line(*this);
779 des->add_node(con);
781 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
782 NetNet::IMPLICIT, pad_width);
783 tmp->data_type(expr_type());
784 tmp->local_flag(true);
785 tmp->set_line(*this);
786 connect(tmp->pin(0), con->pin(0));
788 connect(cat->pin(0), net->pin(0));
789 connect(cat->pin(1), sub->pin(0));
790 connect(cat->pin(2), con->pin(0));
793 return net;
797 * Synthesize a ?: operator as a NetMux device. Connect the condition
798 * expression to the select input, then connect the true and false
799 * expressions to the B and A inputs. This way, when the select input
800 * is one, the B input, which is the true expression, is selected.
802 NetNet* NetETernary::synthesize(Design *des)
804 NetNet*csig = cond_->synthesize(des);
805 NetNet*tsig = true_val_->synthesize(des);
806 NetNet*fsig = false_val_->synthesize(des);
808 perm_string path = csig->scope()->local_symbol();
810 assert(csig->vector_width() == 1);
812 unsigned width=expr_width();
813 NetNet*osig = new NetNet(csig->scope(), path, NetNet::IMPLICIT, width);
814 osig->data_type(expr_type());
815 osig->local_flag(true);
817 /* Make sure both value operands are the right width. */
818 tsig = crop_to_width(des, pad_to_width(des, tsig, width), width);
819 fsig = crop_to_width(des, pad_to_width(des, fsig, width), width);
821 assert(width == tsig->vector_width());
822 assert(width == fsig->vector_width());
824 perm_string oname = csig->scope()->local_symbol();
825 NetMux *mux = new NetMux(csig->scope(), oname, width,
826 2, csig->vector_width());
827 connect(tsig->pin(0), mux->pin_Data(1));
828 connect(fsig->pin(0), mux->pin_Data(0));
829 connect(osig->pin(0), mux->pin_Result());
830 connect(csig->pin(0), mux->pin_Sel());
831 des->add_node(mux);
833 return osig;
837 * When synthesizing a signal expression, it is usually fine to simply
838 * return the NetNet that it refers to. If this is a part select,
839 * though, a bit more work needs to be done. Return a temporary that
840 * represents the connections to the selected bits.
842 * For example, if there is a reg foo, like so:
843 * reg [5:0] foo;
844 * and this expression node represents a part select foo[3:2], then
845 * create a temporary like so:
847 * foo
848 * +---+
849 * | 5 |
850 * +---+
851 * tmp | 4 |
852 * +---+ +---+
853 * | 1 | <---> | 3 |
854 * +---+ +---+
855 * | 0 | <---> | 2 |
856 * +---+ +---+
857 * | 1 |
858 * +---+
859 * | 0 |
860 * +---+
861 * The temporary is marked as a temporary and returned to the
862 * caller. This causes the caller to get only the selected part of the
863 * signal, and when it hooks up to tmp, it hooks up to the right parts
864 * of foo.
866 NetNet* NetESignal::synthesize(Design*des)
868 return net_;
872 * $Log: expr_synth.cc,v $
873 * Revision 1.87 2007/06/02 03:42:12 steve
874 * Properly evaluate scope path expressions.
876 * Revision 1.86 2007/04/15 01:37:29 steve
877 * Allow bit/part select of vectors in continuous assignments.
879 * Revision 1.85 2007/04/12 05:21:54 steve
880 * fix handling of unary reduction logic in certain nets.
882 * Revision 1.84 2007/04/04 02:31:57 steve
883 * Remove useless assert
885 * Revision 1.83 2007/02/05 01:42:31 steve
886 * Set some missing local flags.
888 * Revision 1.82 2007/01/20 02:10:45 steve
889 * Get argument widths right for shift results.
891 * Revision 1.81 2007/01/16 05:44:15 steve
892 * Major rework of array handling. Memories are replaced with the
893 * more general concept of arrays. The NetMemory and NetEMemory
894 * classes are removed from the ivl core program, and the IVL_LPM_RAM
895 * lpm type is removed from the ivl_target API.
897 * Revision 1.80 2006/08/08 05:11:37 steve
898 * Handle 64bit delay constants.
900 * Revision 1.79 2006/07/31 03:50:17 steve
901 * Add support for power in constant expressions.
903 * Revision 1.78 2006/07/08 21:48:46 steve
904 * Handle real valued literals in net contexts.
906 * Revision 1.77 2006/05/01 20:47:59 steve
907 * More explicit datatype setup.
909 * Revision 1.76 2006/05/01 05:40:21 steve
910 * fix net type of multiply output.
912 * Revision 1.75 2006/04/30 05:17:48 steve
913 * Get the data type of part select results right.
915 * Revision 1.74 2006/01/03 05:15:33 steve
916 * Fix the return type of a synthesized divide.
918 * Revision 1.73 2005/09/15 23:04:09 steve
919 * Make sure div, mod and mult nodes have line number info.
921 * Revision 1.72 2005/08/31 05:07:31 steve
922 * Handle memory references is continuous assignments.
924 * Revision 1.71 2005/06/13 23:22:14 steve
925 * use NetPartSelect to shrink part from high bits.
927 * Revision 1.70 2005/06/13 22:26:03 steve
928 * Make synthesized padding vector-aware.
930 * Revision 1.69 2005/05/15 04:47:00 steve
931 * synthesis of Logic and shifts using vector gates.
933 * Revision 1.68 2005/05/06 00:25:13 steve
934 * Handle synthesis of concatenation expressions.
936 * Revision 1.67 2005/04/25 01:30:31 steve
937 * synthesis of add and unary get vector widths right.
939 * Revision 1.66 2005/04/24 23:44:02 steve
940 * Update DFF support to new data flow.
942 * Revision 1.65 2005/03/12 06:43:35 steve
943 * Update support for LPM_MOD.
945 * Revision 1.64 2005/02/19 02:43:38 steve
946 * Support shifts and divide.
948 * Revision 1.63 2005/02/12 06:25:40 steve
949 * Restructure NetMux devices to pass vectors.
950 * Generate NetMux devices from ternary expressions,
951 * Reduce NetMux devices to bufif when appropriate.
953 * Revision 1.62 2005/01/28 05:39:33 steve
954 * Simplified NetMult and IVL_LPM_MULT.
956 * Revision 1.61 2005/01/16 04:20:32 steve
957 * Implement LPM_COMPARE nodes as two-input vector functors.
959 * Revision 1.60 2004/12/11 02:31:26 steve
960 * Rework of internals to carry vectors through nexus instead
961 * of single bits. Make the ivl, tgt-vvp and vvp initial changes
962 * down this path.
964 * Revision 1.59 2004/06/30 02:16:26 steve
965 * Implement signed divide and signed right shift in nets.
967 * Revision 1.58 2004/06/16 16:21:34 steve
968 * Connect rsif of multiply to DataB.
970 * Revision 1.57 2004/06/12 15:00:02 steve
971 * Support / and % in synthesized contexts.
973 * Revision 1.56 2004/06/01 01:04:57 steve
974 * Fix synthesis method for logical and/or
976 * Revision 1.55 2004/02/20 18:53:35 steve
977 * Addtrbute keys are perm_strings.
979 * Revision 1.54 2004/02/18 17:11:56 steve
980 * Use perm_strings for named langiage items.
982 * Revision 1.53 2004/02/15 04:23:48 steve
983 * Fix evaluation of compare to constant expression.
985 * Revision 1.52 2003/11/10 19:39:20 steve
986 * Remove redundant scope tokens.
988 * Revision 1.51 2003/10/27 06:04:21 steve
989 * More flexible width handling for synthesized add.
991 * Revision 1.50 2003/09/26 02:44:27 steve
992 * Assure ternary arguments are wide enough.
994 * Revision 1.49 2003/09/03 23:31:36 steve
995 * Support synthesis of constant downshifts.
997 * Revision 1.48 2003/08/28 04:11:18 steve
998 * Spelling patch.
1000 * Revision 1.47 2003/08/09 03:23:40 steve
1001 * Add support for IVL_LPM_MULT device.
1003 * Revision 1.46 2003/07/26 03:34:42 steve
1004 * Start handling pad of expressions in code generators.
1006 * Revision 1.45 2003/06/24 01:38:02 steve
1007 * Various warnings fixed.
1009 * Revision 1.44 2003/04/19 04:52:56 steve
1010 * Less picky about expression widths while synthesizing ternary.
1012 * Revision 1.43 2003/04/08 05:07:15 steve
1013 * Detect constant shift distances in synthesis.
1015 * Revision 1.42 2003/04/08 04:33:55 steve
1016 * Synthesize shift expressions.
1018 * Revision 1.41 2003/03/06 00:28:41 steve
1019 * All NetObj objects have lex_string base names.
1021 * Revision 1.40 2003/02/26 01:29:24 steve
1022 * LPM objects store only their base names.
1024 * Revision 1.39 2003/01/30 16:23:07 steve
1025 * Spelling fixes.
1027 * Revision 1.38 2003/01/26 21:15:58 steve
1028 * Rework expression parsing and elaboration to
1029 * accommodate real/realtime values and expressions.
1031 * Revision 1.37 2002/11/17 23:37:55 steve
1032 * Magnitude compare to 0.
1034 * Revision 1.36 2002/08/12 01:34:59 steve
1035 * conditional ident string using autoconfig.
1037 * Revision 1.35 2002/07/07 22:31:39 steve
1038 * Smart synthesis of binary AND expressions.
1040 * Revision 1.34 2002/07/05 21:26:17 steve
1041 * Avoid emitting to vvp local net symbols.
1043 * Revision 1.33 2002/05/26 01:39:02 steve
1044 * Carry Verilog 2001 attributes with processes,
1045 * all the way through to the ivl_target API.
1047 * Divide signal reference counts between rval
1048 * and lval references.