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)
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
20 #ident "$Id: expr_synth.cc,v 1.87 2007/06/02 03:42:12 steve Exp $"
29 # include "ivl_assert.h"
31 NetNet
* NetExpr::synthesize(Design
*des
)
33 cerr
<< get_line() << ": internal error: cannot synthesize expression: "
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());
72 adder
->attribute(perm_string::literal("LPM_Direction"), verinum("ADD"));
75 adder
->attribute(perm_string::literal("LPM_Direction"), verinum("SUB"));
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
88 NetNet
* NetEBBits::synthesize(Design
*des
)
90 NetNet
*lsig
= left_
->synthesize(des
);
91 NetNet
*rsig
= right_
->synthesize(des
);
93 NetScope
*scope
= lsig
->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
;
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();
119 gate
= new NetLogic(scope
, oname
, 3, NetLogic::AND
, wid
);
122 gate
= new NetLogic(scope
, oname
, 3, NetLogic::OR
, wid
);
125 gate
= new NetLogic(scope
, oname
, 3, NetLogic::XOR
, wid
);
128 gate
= new NetLogic(scope
, oname
, 3, NetLogic::NOR
, wid
);
131 gate
= new NetLogic(scope
, oname
, 3, NetLogic::XNOR
, wid
);
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);
147 NetNet
* NetEBComp::synthesize(Design
*des
)
150 NetNet
*lsig
= left_
->synthesize(des
);
151 NetNet
*rsig
= right_
->synthesize(des
);
153 NetScope
*scope
= lsig
->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));
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));
197 NetCompare
*dev
= new NetCompare(scope
, scope
->local_symbol(), width
);
198 dev
->set_line(*this);
201 connect(dev
->pin_DataA(), lsig
->pin(0));
202 connect(dev
->pin_DataB(), rsig
->pin(0));
207 connect(dev
->pin_ALB(), osig
->pin(0));
210 connect(dev
->pin_AGB(), osig
->pin(0));
214 connect(dev
->pin_AEB(), osig
->pin(0));
217 connect(dev
->pin_AGEB(), osig
->pin(0));
220 connect(dev
->pin_ALEB(), osig
->pin(0));
224 connect(dev
->pin_ANEB(), osig
->pin(0));
228 cerr
<< get_line() << ": internal error: cannot synthesize "
229 "comparison: " << *this << endl
;
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
;
245 NetNet
* NetEBMult::synthesize(Design
*des
)
247 NetNet
*lsig
= left_
->synthesize(des
);
248 NetNet
*rsig
= right_
->synthesize(des
);
256 NetScope
*scope
= lsig
->scope();
259 NetMult
*mult
= new NetMult(scope
, scope
->local_symbol(),
261 lsig
->vector_width(),
262 rsig
->vector_width());
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));
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);
299 NetDivide
*div
= new NetDivide(scope
, scope
->local_symbol(),
301 lsig
->vector_width(),
302 rsig
->vector_width());
303 div
->set_line(*this);
306 connect(div
->pin_DataA(), lsig
->pin(0));
307 connect(div
->pin_DataB(), rsig
->pin(0));
308 connect(div
->pin_Result(),osig
->pin(0));
313 NetModulo
*div
= new NetModulo(scope
, scope
->local_symbol(),
315 lsig
->vector_width(),
316 rsig
->vector_width());
317 div
->set_line(*this);
320 connect(div
->pin_DataA(), lsig
->pin(0));
321 connect(div
->pin_DataB(), rsig
->pin(0));
322 connect(div
->pin_Result(),osig
->pin(0));
327 cerr
<< get_line() << ": internal error: "
328 << "NetEBDiv has unexpeced op() code: "
340 NetNet
* NetEBLogic::synthesize(Design
*des
)
342 NetNet
*lsig
= left_
->synthesize(des
);
343 NetNet
*rsig
= right_
->synthesize(des
);
351 NetScope
*scope
= lsig
->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);
362 /* Logic OR can handle the reduction *and* the logical
363 comparison with a single wide OR gate. So handle this
366 perm_string oname
= scope
->local_symbol();
368 NetLogic
*olog
= new NetLogic(scope
, oname
,
369 lsig
->pin_count()+rsig
->pin_count()+1,
372 connect(osig
->pin(0), olog
->pin(0));
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
));
387 /* Create the logic AND gate. This is a single bit
388 output, with inputs for each of the operands. */
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));
397 /* XXXX Here, I need to reduce the parameters with
401 /* By this point, the left and right parameters have been
402 reduced to single bit values. Now we just connect them to
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));
415 NetNet
* NetEBShift::synthesize(Design
*des
)
417 if (! dynamic_cast<NetEConst
*>(right_
)) {
418 NetExpr
*tmp
= right_
->eval_tree();
425 NetNet
*lsig
= left_
->synthesize(des
);
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();
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(),
465 /* Detect the special case that the shift is the size of
466 the whole expression. Simply connect the pad to the
468 if (ushift
>= osig
->vector_width()) {
469 connect(zcon
->pin(0), osig
->pin(0));
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,
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);
499 connect(ccat
->pin(0), osig
->pin(0));
502 connect(ccat
->pin(1), zsig
->pin(0));
503 connect(ccat
->pin(2), psig
->pin(0));
506 connect(ccat
->pin(1), psig
->pin(0));
507 connect(ccat
->pin(2), zsig
->pin(0));
513 NetNet
*rsig
= right_
->synthesize(des
);
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);
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));
539 NetNet
* NetEConcat::synthesize(Design
*des
)
541 /* First, synthesize the operands. */
542 NetNet
**tmp
= new NetNet
*[parms_
.count()];
544 for (unsigned idx
= 0 ; idx
< parms_
.count() ; idx
+= 1) {
545 tmp
[idx
] = parms_
[idx
]->synthesize(des
);
554 NetScope
*scope
= tmp
[0]->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));
582 NetNet
* NetEConst::synthesize(Design
*des
)
584 NetScope
*scope
= des
->find_root_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));
602 * Create a NetLiteral object to represent real valued constants.
604 NetNet
* NetECReal::synthesize(Design
*des
)
606 NetScope
*scope
= des
->find_root_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_
);
619 con
->set_line(*this);
621 connect(osig
->pin(0), con
->pin(0));
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();
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();
647 gate
= new NetLogic(scope
, oname
, 2, NetLogic::NOT
, width
);
653 connect(osig
->pin(0), gate
->pin(0));
654 connect(isig
->pin(0), gate
->pin(1));
661 NetNet
* NetEUReduce::synthesize(Design
*des
)
663 NetNet
*isig
= expr_
->synthesize(des
);
665 NetScope
*scope
= isig
->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
;
678 rtype
= NetUReduce::NOR
;
681 rtype
= NetUReduce::AND
;
684 rtype
= NetUReduce::OR
;
687 rtype
= NetUReduce::XOR
;
690 rtype
= NetUReduce::XNOR
;
693 rtype
= NetUReduce::XNOR
;
696 cerr
<< get_line() << ": internal error: "
697 << "Unable to synthesize " << *this << "." << endl
;
701 NetUReduce
*gate
= new NetUReduce(scope
, scope
->local_symbol(),
702 rtype
, isig
->vector_width());
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
));
712 NetNet
* NetESelect::synthesize(Design
*des
)
715 NetNet
*sub
= expr_
->synthesize(des
);
719 NetScope
*scope
= sub
->scope();
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.
727 off
= base_
->synthesize(des
);
729 NetPartSelect
*sel
= new NetPartSelect(sub
, off
, expr_width());
730 sel
->set_line(*this);
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);
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
748 if (sub
->vector_width() == expr_width())
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);
762 NetSignExtend
*pad
= new NetSignExtend(scope
,
763 scope
->local_symbol(),
765 pad
->set_line(*this);
768 connect(pad
->pin(1), sub
->pin(0));
769 connect(pad
->pin(0), net
->pin(0));
773 NetConcat
*cat
= new NetConcat(scope
, scope
->local_symbol(),
775 cat
->set_line(*this);
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(),
783 con
->set_line(*this);
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));
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());
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:
849 * and this expression node represents a part select foo[3:2], then
850 * create a temporary like so:
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
871 NetNet
* NetESignal::synthesize(Design
*des
)