Support for wide modulus operations.
[iverilog.git] / expr_synth.cc
blob2e08cab5f8f1f780a43dd1b2ecf2ddd6a2c329bf
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(),
565 parms_.count() * repeat());
566 concat->set_line(*this);
567 des->add_node(concat);
568 connect(concat->pin(0), osig->pin(0));
570 unsigned cur_pin = 1;
571 for (unsigned rpt = 0; rpt < repeat(); rpt += 1) {
572 for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
573 connect(concat->pin(cur_pin), tmp[parms_.count()-idx-1]->pin(0));
574 cur_pin += 1;
578 delete[]tmp;
579 return osig;
582 NetNet* NetEConst::synthesize(Design*des)
584 NetScope*scope = des->find_root_scope();
585 assert(scope);
587 perm_string path = scope->local_symbol();
588 unsigned width=expr_width();
590 NetNet*osig = new NetNet(scope, path, NetNet::IMPLICIT, width-1,0);
591 osig->local_flag(true);
592 osig->data_type(IVL_VT_LOGIC);
593 osig->set_signed(has_sign());
594 NetConst*con = new NetConst(scope, scope->local_symbol(), value());
595 connect(osig->pin(0), con->pin(0));
597 des->add_node(con);
598 return osig;
602 * Create a NetLiteral object to represent real valued constants.
604 NetNet* NetECReal::synthesize(Design*des)
606 NetScope*scope = des->find_root_scope();
607 assert(scope);
609 perm_string path = scope->local_symbol();
611 NetNet*osig = new NetNet(scope, path, NetNet::WIRE, 1);
612 osig->local_flag(true);
613 osig->data_type(IVL_VT_REAL);
614 osig->set_signed(has_sign());
615 osig->set_line(*this);
617 NetLiteral*con = new NetLiteral(scope, scope->local_symbol(), value_);
618 des->add_node(con);
619 con->set_line(*this);
621 connect(osig->pin(0), con->pin(0));
622 return osig;
626 * The bitwise unary logic operator (there is only one) is turned
627 * into discrete gates just as easily as the binary ones above.
629 NetNet* NetEUBits::synthesize(Design*des)
631 NetNet*isig = expr_->synthesize(des);
633 NetScope*scope = isig->scope();
634 assert(scope);
636 unsigned width = isig->vector_width();
637 NetNet*osig = new NetNet(scope, scope->local_symbol(),
638 NetNet::IMPLICIT, width);
639 osig->data_type(expr_type());
640 osig->local_flag(true);
642 perm_string oname = scope->local_symbol();
643 NetLogic*gate;
645 switch (op()) {
646 case '~':
647 gate = new NetLogic(scope, oname, 2, NetLogic::NOT, width);
648 break;
649 default:
650 assert(0);
653 connect(osig->pin(0), gate->pin(0));
654 connect(isig->pin(0), gate->pin(1));
656 des->add_node(gate);
658 return osig;
661 NetNet* NetEUReduce::synthesize(Design*des)
663 NetNet*isig = expr_->synthesize(des);
665 NetScope*scope = isig->scope();
666 assert(scope);
668 NetNet*osig = new NetNet(scope, scope->local_symbol(),
669 NetNet::IMPLICIT, 1);
670 osig->data_type(expr_type());
671 osig->local_flag(true);
673 NetUReduce::TYPE rtype = NetUReduce::NONE;
675 switch (op()) {
676 case 'N':
677 case '!':
678 rtype = NetUReduce::NOR;
679 break;
680 case '&':
681 rtype = NetUReduce::AND;
682 break;
683 case '|':
684 rtype = NetUReduce::OR;
685 break;
686 case '^':
687 rtype = NetUReduce::XOR;
688 break;
689 case 'A':
690 rtype = NetUReduce::XNOR;
691 break;
692 case 'X':
693 rtype = NetUReduce::XNOR;
694 break;
695 default:
696 cerr << get_line() << ": internal error: "
697 << "Unable to synthesize " << *this << "." << endl;
698 return 0;
701 NetUReduce*gate = new NetUReduce(scope, scope->local_symbol(),
702 rtype, isig->vector_width());
704 des->add_node(gate);
705 connect(gate->pin(0), osig->pin(0));
706 for (unsigned idx = 0 ; idx < isig->pin_count() ; idx += 1)
707 connect(gate->pin(1+idx), isig->pin(idx));
709 return osig;
712 NetNet* NetESelect::synthesize(Design *des)
715 NetNet*sub = expr_->synthesize(des);
716 if (sub == 0)
717 return 0;
719 NetScope*scope = sub->scope();
721 NetNet*off = 0;
723 // This handles the case that the NetESelect exists to do an
724 // actual part/bit select. Generate a NetPartSelect object to
725 // do the work, and replace "sub" with the selected output.
726 if (base_ != 0) {
727 off = base_->synthesize(des);
729 NetPartSelect*sel = new NetPartSelect(sub, off, expr_width());
730 sel->set_line(*this);
731 des->add_node(sel);
733 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
734 NetNet::IMPLICIT, expr_width());
735 tmp->data_type(sub->data_type());
736 tmp->local_flag(true);
737 tmp->set_line(*this);
738 sub = tmp;
739 connect(sub->pin(0), sel->pin(0));
743 // Now look for the case that the NetESelect actually exists
744 // to change the width of the expression. (i.e. to do
745 // padding.) If this was for an actual part select that at
746 // this point the output vector_width is exactly right, and we
747 // are done.
748 if (sub->vector_width() == expr_width())
749 return sub;
751 // The vector_width is not exactly right, so the source is
752 // probably asking for padding. Create nodes to do sign
753 // extension or 0 extension, depending on the has_sign() mode
754 // of the expression.
756 NetNet*net = new NetNet(scope, scope->local_symbol(),
757 NetNet::IMPLICIT, expr_width());
758 net->data_type(expr_type());
759 net->local_flag(true);
760 net->set_line(*this);
761 if (has_sign()) {
762 NetSignExtend*pad = new NetSignExtend(scope,
763 scope->local_symbol(),
764 expr_width());
765 pad->set_line(*this);
766 des->add_node(pad);
768 connect(pad->pin(1), sub->pin(0));
769 connect(pad->pin(0), net->pin(0));
771 } else {
773 NetConcat*cat = new NetConcat(scope, scope->local_symbol(),
774 expr_width(), 2);
775 cat->set_line(*this);
776 des->add_node(cat);
778 assert(expr_width() > sub->vector_width());
779 unsigned pad_width = expr_width() - sub->vector_width();
780 verinum pad((uint64_t)0, pad_width);
781 NetConst*con = new NetConst(scope, scope->local_symbol(),
782 pad);
783 con->set_line(*this);
784 des->add_node(con);
786 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
787 NetNet::IMPLICIT, pad_width);
788 tmp->data_type(expr_type());
789 tmp->local_flag(true);
790 tmp->set_line(*this);
791 connect(tmp->pin(0), con->pin(0));
793 connect(cat->pin(0), net->pin(0));
794 connect(cat->pin(1), sub->pin(0));
795 connect(cat->pin(2), con->pin(0));
798 return net;
802 * Synthesize a ?: operator as a NetMux device. Connect the condition
803 * expression to the select input, then connect the true and false
804 * expressions to the B and A inputs. This way, when the select input
805 * is one, the B input, which is the true expression, is selected.
807 NetNet* NetETernary::synthesize(Design *des)
809 NetNet*csig = cond_->synthesize(des);
810 NetNet*tsig = true_val_->synthesize(des);
811 NetNet*fsig = false_val_->synthesize(des);
813 perm_string path = csig->scope()->local_symbol();
815 assert(csig->vector_width() == 1);
817 unsigned width=expr_width();
818 NetNet*osig = new NetNet(csig->scope(), path, NetNet::IMPLICIT, width);
819 osig->data_type(expr_type());
820 osig->local_flag(true);
822 /* Make sure both value operands are the right width. */
823 tsig = crop_to_width(des, pad_to_width(des, tsig, width), width);
824 fsig = crop_to_width(des, pad_to_width(des, fsig, width), width);
826 assert(width == tsig->vector_width());
827 assert(width == fsig->vector_width());
829 perm_string oname = csig->scope()->local_symbol();
830 NetMux *mux = new NetMux(csig->scope(), oname, width,
831 2, csig->vector_width());
832 connect(tsig->pin(0), mux->pin_Data(1));
833 connect(fsig->pin(0), mux->pin_Data(0));
834 connect(osig->pin(0), mux->pin_Result());
835 connect(csig->pin(0), mux->pin_Sel());
836 des->add_node(mux);
838 return osig;
842 * When synthesizing a signal expression, it is usually fine to simply
843 * return the NetNet that it refers to. If this is a part select,
844 * though, a bit more work needs to be done. Return a temporary that
845 * represents the connections to the selected bits.
847 * For example, if there is a reg foo, like so:
848 * reg [5:0] foo;
849 * and this expression node represents a part select foo[3:2], then
850 * create a temporary like so:
852 * foo
853 * +---+
854 * | 5 |
855 * +---+
856 * tmp | 4 |
857 * +---+ +---+
858 * | 1 | <---> | 3 |
859 * +---+ +---+
860 * | 0 | <---> | 2 |
861 * +---+ +---+
862 * | 1 |
863 * +---+
864 * | 0 |
865 * +---+
866 * The temporary is marked as a temporary and returned to the
867 * caller. This causes the caller to get only the selected part of the
868 * signal, and when it hooks up to tmp, it hooks up to the right parts
869 * of foo.
871 NetNet* NetESignal::synthesize(Design*des)
873 return net_;