Various improgements to expression ::synthesize methods

Since NetExpr::synthesize methods were rarely used, then had a lot
of bugs. Now that continuous assign uses these methods, these bugs
must be fixed.

Binary and Unary minus properly pad/extens its arguments,
Case compare generates correct code,
Divide properly takes on signed flag,
Signed right shift sign-extends its argument to prevent loss of sign bits
and uses the NetSignExtend instead of simple padding,
Use the correct target node for reduction NAND,
Properly handle constant arguments of NetESelect

Handle some exressions that were not handled before, include abs()
and POW.
This commit is contained in:
Stephen Williams 2008-08-17 08:21:24 -07:00
parent e8804500b0
commit a8ad505af7
3 changed files with 226 additions and 39 deletions

View File

@ -91,7 +91,7 @@ NetNet* NetExpr::synthesize(Design*des, NetScope*scope)
*/
NetNet* NetEBAdd::synthesize(Design*des, NetScope*scope)
{
assert((op()=='+') || (op()=='-'));
ivl_assert(*this, (op()=='+') || (op()=='-'));
NetNet *lsig=0, *rsig=0;
bool real_args=false;
@ -220,8 +220,14 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope)
width = lsig->vector_width();
if (rsig->vector_width() > width) width = rsig->vector_width();
lsig = pad_to_width(des, lsig, width);
rsig = pad_to_width(des, rsig, width);
if (lsig->get_signed())
lsig = pad_to_width_signed(des, lsig, width);
else
lsig = pad_to_width(des, lsig, width);
if (rsig->get_signed())
rsig = pad_to_width_signed(des, rsig, width);
else
rsig = pad_to_width(des, rsig, width);
}
NetNet*osig = new NetNet(scope, scope->local_symbol(),
@ -231,10 +237,30 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope)
osig->data_type(IVL_VT_LOGIC);
bool signed_compare = lsig->get_signed() && rsig->get_signed();
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Comparison (" << op_ << ")"
<< " is " << (signed_compare? "signed" : "unsigned")
<< endl;
cerr << get_fileline() << ": : lsig is "
<< (lsig->get_signed()? "signed" : "unsigned")
<< " rsig is " << (rsig->get_signed()? "signed" : "unsigned")
<< endl;
}
if (op_ == 'E' || op_ == 'N') {
NetCaseCmp*gate = new NetCaseCmp(scope, scope->local_symbol(),
width, op_=='E'?true:false);
gate->set_line(*this);
connect(gate->pin(0), osig->pin(0));
connect(gate->pin(1), lsig->pin(0));
connect(gate->pin(2), rsig->pin(0));
des->add_node(gate);
return osig;
}
/* Handle the special case of a single bit equality
operation. Make an XNOR gate instead of a comparator. */
if ((width == 1) && ((op_ == 'e') || (op_ == 'E')) && !real_args) {
if ((width == 1) && (op_ == 'e') && !real_args) {
NetLogic*gate = new NetLogic(scope, scope->local_symbol(),
3, NetLogic::XNOR, 1);
gate->set_line(*this);
@ -248,7 +274,7 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope)
/* Handle the special case of a single bit inequality
operation. This is similar to single bit equality, but uses
an XOR instead of an XNOR gate. */
if ((width == 1) && ((op_ == 'n') || (op_ == 'N')) && !real_args) {
if ((width == 1) && (op_ == 'n') && !real_args) {
NetLogic*gate = new NetLogic(scope, scope->local_symbol(),
3, NetLogic::XOR, 1);
gate->set_line(*this);
@ -404,6 +430,7 @@ NetNet* NetEBDiv::synthesize(Design*des, NetScope*scope)
NetNet::IMPLICIT, width);
osig->set_line(*this);
osig->data_type(lsig->data_type());
osig->set_signed(has_sign());
osig->local_flag(true);
switch (op()) {
@ -414,6 +441,7 @@ NetNet* NetEBDiv::synthesize(Design*des, NetScope*scope)
lsig->vector_width(),
rsig->vector_width());
div->set_line(*this);
div->set_signed(has_sign());
des->add_node(div);
connect(div->pin_DataA(), lsig->pin(0));
@ -552,8 +580,8 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope)
return 0;
}
bool right_flag = op_ == 'r' || op_ == 'R';
bool signed_flag = op_ == 'R';
const bool right_flag = op_ == 'r' || op_ == 'R';
const bool signed_flag = op_ == 'R';
/* Detect the special case where the shift amount is
constant. Evaluate the shift amount, and simply reconnect
@ -562,7 +590,7 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope)
verinum shift_v = rcon->value();
long shift = shift_v.as_long();
if (op() == 'r')
if (right_flag)
shift = 0-shift;
if (shift == 0)
@ -575,34 +603,13 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope)
// ushift is the amount of pad created by the shift.
unsigned long ushift = shift>=0? shift : -shift;
if (ushift > osig->vector_width())
ushift = osig->vector_width();
ivl_assert(*this, ushift < osig->vector_width());
// part_width is the bits of the vector that survive the shift.
unsigned long part_width = osig->vector_width() - ushift;
verinum znum (verinum::V0, ushift, true);
NetConst*zcon = new NetConst(scope, scope->local_symbol(),
znum);
des->add_node(zcon);
/* Detect the special case that the shift is the size of
the whole expression. Simply connect the pad to the
osig and escape. */
if (ushift >= osig->vector_width()) {
connect(zcon->pin(0), osig->pin(0));
return osig;
}
NetNet*zsig = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, znum.len());
zsig->data_type(osig->data_type());
zsig->local_flag(true);
zsig->set_line(*this);
connect(zcon->pin(0), zsig->pin(0));
/* Create a part select to reduce the width of the lsig
to the amount left by the shift. */
// Create a part select to reduce the width of the lsig
// to the amount left by the shift.
NetPartSelect*psel = new NetPartSelect(lsig, shift<0? ushift : 0,
part_width,
NetPartSelect::VP);
@ -615,6 +622,34 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope)
psig->set_line(*this);
connect(psig->pin(0), psel->pin(0));
// Handle the special case of a signed right shift. In
// this case, use the NetSignExtend device to pad the
// result to the desired width.
if (signed_flag && right_flag) {
NetSignExtend*pad = new NetSignExtend(scope, scope->local_symbol(),
osig->vector_width());
des->add_node(pad);
pad->set_line(*this);
connect(pad->pin(1), psig->pin(0));
connect(pad->pin(0), osig->pin(0));
return osig;
}
// Other cases are handled by zero-extending on the
// proper end.
verinum znum (verinum::V0, ushift, true);
NetConst*zcon = new NetConst(scope, scope->local_symbol(),
znum);
des->add_node(zcon);
NetNet*zsig = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, znum.len());
zsig->data_type(osig->data_type());
zsig->local_flag(true);
zsig->set_line(*this);
connect(zcon->pin(0), zsig->pin(0));
NetConcat*ccat = new NetConcat(scope, scope->local_symbol(),
osig->vector_width(), 2);
ccat->set_line(*this);
@ -674,7 +709,7 @@ NetNet* NetEConcat::synthesize(Design*des, NetScope*scope)
if (flag == false)
return 0;
assert(tmp[0]);
ivl_assert(*this, tmp[0]);
/* Make a NetNet object to carry the output vector. */
perm_string path = scope->local_symbol();
@ -692,7 +727,9 @@ NetNet* NetEConcat::synthesize(Design*des, NetScope*scope)
unsigned cur_pin = 1;
for (unsigned rpt = 0; rpt < repeat(); rpt += 1) {
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
connect(concat->pin(cur_pin), tmp[parms_.count()-idx-1]->pin(0));
unsigned concat_item = parms_.count()-idx-1;
ivl_assert(*this, tmp[concat_item]);
connect(concat->pin(cur_pin), tmp[concat_item]->pin(0));
cur_pin += 1;
}
}
@ -787,9 +824,28 @@ NetNet* NetEUnary::synthesize(Design*des, NetScope*scope)
return expr_->synthesize(des, scope);
if (op_ == '-') {
NetExpr*tmp = make_sub_expr(0, expr_);
NetNet*sig = tmp->synthesize(des, scope);
delete tmp;
NetNet*sig = expr_->synthesize(des, scope);
sig = sub_net_from(des, scope, 0, sig);
return sig;
}
if (op_ == 'm') {
NetNet*sub = expr_->synthesize(des, scope);
if (expr_->has_sign() == false)
return sub;
NetNet*sig = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, sub->vector_width());
sig->set_line(*this);
sig->local_flag(true);
sig->data_type(sub->data_type());
NetAbs*tmp = new NetAbs(scope, scope->local_symbol(), sub->vector_width());
des->add_node(tmp);
tmp->set_line(*this);
connect(tmp->pin(1), sub->pin(0));
connect(tmp->pin(0), sig->pin(0));
return sig;
}
@ -835,7 +891,7 @@ NetNet* NetEUReduce::synthesize(Design*des, NetScope*scope)
rtype = NetUReduce::XOR;
break;
case 'A':
rtype = NetUReduce::XNOR;
rtype = NetUReduce::NAND;
break;
case 'X':
rtype = NetUReduce::XNOR;
@ -857,6 +913,14 @@ NetNet* NetEUReduce::synthesize(Design*des, NetScope*scope)
return osig;
}
/*
* Turn a part/bit select expression into gates.
* We know some things about the expression that elaboration enforces
* for us:
*
* - Expression elaboration already converted the offset expression into
* cannonical form, so we don't have to worry about that here.
*/
NetNet* NetESelect::synthesize(Design *des, NetScope*scope)
{
@ -866,6 +930,79 @@ NetNet* NetESelect::synthesize(Design *des, NetScope*scope)
NetNet*off = 0;
// Detect the special case that there is a base expression and
// it is constant. In this case we can generate fixed part selects.
if (NetEConst*base_const = dynamic_cast<NetEConst*>(base_)) {
verinum base_tmp = base_const->value();
ivl_assert(*this, base_tmp.is_defined());
long base_val = base_tmp.as_long();
unsigned select_width = expr_width();
// Any below X bits?
NetNet*below = 0;
if (base_val < 0) {
unsigned below_width = abs(base_val);
base_val = 0;
ivl_assert(*this, below_width < select_width);
select_width -= below_width;
below = make_const_x(des, scope, below_width);
below->set_line(*this);
}
// Any above bits?.
NetNet*above = 0;
if (base_val+select_width > sub->vector_width()) {
select_width = sub->vector_width() - base_val;
unsigned above_width = expr_width() - select_width;
above = make_const_x(des, scope, above_width);
above->set_line(*this);
}
// Make the make part select.
NetPartSelect*sel = new NetPartSelect(sub, base_val, select_width,
NetPartSelect::VP);
des->add_node(sel);
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, select_width);
tmp->data_type(sub->data_type());
tmp->local_flag(true);
tmp->set_line(*this);
connect(sel->pin(0), tmp->pin(0));
unsigned concat_count = 1;
if (above)
concat_count += 1;
if (below)
concat_count += 1;
if (concat_count > 1) {
NetConcat*cat = new NetConcat(scope, scope->local_symbol(),
expr_width(), concat_count);
cat->set_line(*this);
des->add_node(cat);
if (below) {
connect(cat->pin(1), below->pin(0));
connect(cat->pin(2), tmp->pin(0));
} else {
connect(cat->pin(1), tmp->pin(0));
}
if (above) {
connect(cat->pin(concat_count), above->pin(0));
}
tmp = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, expr_width());
tmp->data_type(sub->data_type());
tmp->local_flag(true);
tmp->set_line(*this);
connect(cat->pin(0), tmp->pin(0));
}
return tmp;
}
// This handles the case that the NetESelect exists to do an
// actual part/bit select. Generate a NetPartSelect object to
// do the work, and replace "sub" with the selected output.
@ -977,7 +1114,7 @@ NetNet* NetETernary::synthesize(Design *des, NetScope*scope)
perm_string path = csig->scope()->local_symbol();
assert(csig->vector_width() == 1);
ivl_assert(*this, csig->vector_width() == 1);
unsigned width=expr_width();
NetNet*osig = new NetNet(csig->scope(), path, NetNet::IMPLICIT, width);

View File

@ -76,6 +76,36 @@ NetNet* add_to_net(Design*des, NetNet*sig, long val)
#endif
}
NetNet* sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig)
{
verinum zero ((uint64_t)0, sig->vector_width());
NetConst*zero_obj = new NetConst(scope, scope->local_symbol(), zero);
des->add_node(zero_obj);
NetNet*zero_net = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, sig->vector_width());
zero_net->data_type(sig->data_type());
zero_net->local_flag(true);
connect(zero_net->pin(0), zero_obj->pin(0));
NetAddSub*adder = new NetAddSub(scope, scope->local_symbol(), sig->vector_width());
des->add_node(adder);
adder->attribute(perm_string::literal("LPM_Direction"), verinum("SUB"));
connect(zero_net->pin(0), adder->pin_DataA());
connect(adder->pin_DataB(), sig->pin(0));
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, sig->vector_width());
tmp->data_type(sig->data_type());
tmp->local_flag(true);
connect(adder->pin_Result(), tmp->pin(0));
return tmp;
}
NetNet* cast_to_int(Design*des, NetScope*scope, NetNet*src, unsigned wid)
{
if (src->data_type() != IVL_VT_REAL)
@ -170,6 +200,20 @@ NetEConst* make_const_x(unsigned long wid)
return resx;
}
NetNet* make_const_x(Design*des, NetScope*scope, unsigned long wid)
{
verinum xxx (verinum::Vx, wid);
NetConst*res = new NetConst(scope, scope->local_symbol(), xxx);
des->add_node(res);
NetNet*sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, wid);
sig->local_flag(true);
sig->data_type(IVL_VT_LOGIC);
connect(sig->pin(0), res->pin(0));
return sig;
}
NetExpr* condition_reduce(NetExpr*expr)
{
if (expr->expr_width() == 1)

View File

@ -91,6 +91,7 @@ extern NetNet*crop_to_width(Design*des, NetNet*n, unsigned w);
* return a new NetNet value that is the output of an addition.
*/
extern NetNet*add_to_net(Design*des, NetNet*sig, long val);
extern NetNet*sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig);
/*
* These functions make various sorts of expressions, given operands
@ -114,6 +115,11 @@ extern NetExpr*make_sub_expr(long val, NetExpr*expr);
*/
extern NetEConst*make_const_x(unsigned long wid);
/*
* Make A const net
*/
extern NetNet* make_const_x(Design*des, NetScope*scope, unsigned long wid);
/*
* In some cases the lval is accessible as a pointer to the head of
* a list of NetAssign_ objects. This function returns the width of