Merge branch 'elaborate-net-rework'

This commit is contained in:
Stephen Williams 2008-09-08 18:02:51 -07:00
commit 90f55a1d00
24 changed files with 1020 additions and 635 deletions

View File

@ -101,7 +101,7 @@ static NetExpr*calculate_val(Design*des, NetScope*scope, const PExpr*expr)
return dex; return dex;
} }
static NetExpr* make_delay_nets(Design*des, NetExpr*expr) static NetExpr* make_delay_nets(Design*des, NetScope*scope, NetExpr*expr)
{ {
if (dynamic_cast<NetESignal*> (expr)) if (dynamic_cast<NetESignal*> (expr))
return expr; return expr;
@ -109,7 +109,7 @@ static NetExpr* make_delay_nets(Design*des, NetExpr*expr)
if (dynamic_cast<NetEConst*> (expr)) if (dynamic_cast<NetEConst*> (expr))
return expr; return expr;
NetNet*sig = expr->synthesize(des); NetNet*sig = expr->synthesize(des, scope);
if (sig == 0) { if (sig == 0) {
cerr << expr->get_fileline() << ": error: Expression " << *expr cerr << expr->get_fileline() << ": error: Expression " << *expr
<< " is not suitable for delay expression." << endl; << " is not suitable for delay expression." << endl;
@ -132,17 +132,17 @@ void PDelays::eval_delays(Design*des, NetScope*scope,
if (delay_[0]) { if (delay_[0]) {
rise_time = calculate_val(des, scope, delay_[0]); rise_time = calculate_val(des, scope, delay_[0]);
if (as_nets_flag) if (as_nets_flag)
rise_time = make_delay_nets(des, rise_time); rise_time = make_delay_nets(des, scope, rise_time);
if (delay_[1]) { if (delay_[1]) {
fall_time = calculate_val(des, scope, delay_[1]); fall_time = calculate_val(des, scope, delay_[1]);
if (as_nets_flag) if (as_nets_flag)
fall_time = make_delay_nets(des, fall_time); fall_time = make_delay_nets(des, scope, fall_time);
if (delay_[2]) { if (delay_[2]) {
decay_time = calculate_val(des, scope, delay_[2]); decay_time = calculate_val(des, scope, delay_[2]);
if (as_nets_flag) if (as_nets_flag)
decay_time = make_delay_nets(des, decay_time); decay_time = make_delay_nets(des, scope, decay_time);
} else { } else {
if (rise_time < fall_time) if (rise_time < fall_time)

12
PExpr.h
View File

@ -53,7 +53,7 @@ class PExpr : public LineInfo {
// be. It is used by elaboration of assignments to figure out // be. It is used by elaboration of assignments to figure out
// the width of the expression. // the width of the expression.
// //
// The "min" is the width of the local context, so it the // The "min" is the width of the local context, so is the
// minimum width that this function should return. Initially // minimum width that this function should return. Initially
// this is the same as the lval width. // this is the same as the lval width.
// //
@ -492,6 +492,10 @@ class PEUnary : public PExpr {
virtual void dump(ostream&out) const; virtual void dump(ostream&out) const;
virtual unsigned test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
bool&unsized_flag) const;
virtual bool elaborate_sig(Design*des, NetScope*scope) const; virtual bool elaborate_sig(Design*des, NetScope*scope) const;
virtual NetNet* elaborate_net(Design*des, NetScope*scope, virtual NetNet* elaborate_net(Design*des, NetScope*scope,
@ -575,6 +579,10 @@ class PEBinary : public PExpr {
NetExpr*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const; NetExpr*elaborate_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
NetExpr*elaborate_eval_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const; NetExpr*elaborate_eval_expr_base_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
NetExpr*elaborate_expr_base_lshift_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
NetExpr*elaborate_expr_base_rshift_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
NetExpr*elaborate_expr_base_add_(Design*, NetExpr*lp, NetExpr*rp, int use_wid) const;
static void suppress_operand_sign_if_needed_(NetExpr*lp, NetExpr*rp); static void suppress_operand_sign_if_needed_(NetExpr*lp, NetExpr*rp);
private: private:
@ -679,7 +687,7 @@ class PETernary : public PExpr {
const NetExpr* decay, const NetExpr* decay,
Link::strength_t drive0, Link::strength_t drive0,
Link::strength_t drive1) const; Link::strength_t drive1) const;
virtual NetETernary*elaborate_expr(Design*des, NetScope*, virtual NetExpr*elaborate_expr(Design*des, NetScope*,
int expr_width, bool sys_task_arg) const; int expr_width, bool sys_task_arg) const;
virtual NetETernary*elaborate_pexpr(Design*des, NetScope*sc) const; virtual NetETernary*elaborate_pexpr(Design*des, NetScope*sc) const;
virtual verinum* eval_const(Design*des, NetScope*sc) const; virtual verinum* eval_const(Design*des, NetScope*sc) const;

View File

@ -103,6 +103,7 @@ class PAssign_ : public Statement {
protected: protected:
NetAssign_* elaborate_lval(Design*, NetScope*scope) const; NetAssign_* elaborate_lval(Design*, NetScope*scope) const;
NetExpr* elaborate_rval_(Design*, NetScope*, unsigned lv_width) const;
PExpr* delay_; PExpr* delay_;
PEventStatement*event_; PEventStatement*event_;

View File

@ -567,8 +567,14 @@ void NetReplicate::dump_node(ostream&o, unsigned ind) const
void NetSignExtend::dump_node(ostream&o, unsigned ind) const void NetSignExtend::dump_node(ostream&o, unsigned ind) const
{ {
o << setw(ind) << "" << "NetSignExtend: " o << setw(ind) << "" << "NetSignExtend: " << name();
<< name() << " output width=" << width_ << endl; if (rise_time())
o << " #(" << *rise_time()
<< "," << *fall_time()
<< "," << *decay_time() << ")";
else
o << " #(.,.,.)";
o << " output width=" << width_ << endl;
dump_node_pins(o, ind+4); dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4); dump_obj_attr(o, ind+4);
} }

View File

@ -148,8 +148,8 @@ NetExpr* PEBinary::elaborate_eval_expr_base_(Design*des,
* the correct NetEBinary object and connect the parameters. * the correct NetEBinary object and connect the parameters.
*/ */
NetExpr* PEBinary::elaborate_expr_base_(Design*des, NetExpr* PEBinary::elaborate_expr_base_(Design*des,
NetExpr*lp, NetExpr*rp, NetExpr*lp, NetExpr*rp,
int expr_wid) const int expr_wid) const
{ {
bool flag; bool flag;
@ -180,6 +180,13 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des,
break; break;
case '*': case '*':
// Multiply will guess a width that is the sum of the
// widths of the operand. If that sum is too small, then
// pad one of the arguments enough that the sum is the
// desired width.
if (expr_wid > (long)(lp->expr_width() + rp->expr_width()))
lp = pad_to_width(lp, expr_wid - rp->expr_width());
tmp = new NetEBMult(op_, lp, rp); tmp = new NetEBMult(op_, lp, rp);
tmp->set_line(*this); tmp->set_line(*this);
break; break;
@ -203,60 +210,12 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des,
break; break;
case 'l': // << case 'l': // <<
if (NetEConst*lpc = dynamic_cast<NetEConst*> (lp)) { tmp = elaborate_expr_base_lshift_(des, lp, rp, expr_wid);
if (NetEConst*rpc = dynamic_cast<NetEConst*> (rp)) {
// Handle the super-special case that both
// operands are constants. Precalculate the
// entire value here.
verinum lpval = lpc->value();
unsigned shift = rpc->value().as_ulong();
verinum result = lpc->value() << shift;
// If the l-value has explicit size, or
// there is a context determined size, use that.
if (lpval.has_len() || expr_wid > 0) {
int use_len = lpval.len();
if (expr_wid < use_len)
use_len = expr_wid;
result = verinum(result, lpval.len());
}
tmp = new NetEConst(result);
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Precalculate " << *this
<< " to constant " << *tmp << endl;
} else {
// Handle the special case that the left
// operand is constant. If it is unsized, we
// may have to expand it to an integer width.
verinum lpval = lpc->value();
if (lpval.len() < integer_width && !lpval.has_len()) {
lpval = verinum(lpval, integer_width);
lpc = new NetEConst(lpval);
lpc->set_line(*lp);
}
tmp = new NetEBShift(op_, lpc, rp);
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Adjust " << *this
<< " to this " << *tmp
<< " to allow for integer widths." << endl;
}
} else {
// Left side is not constant, so handle it the
// default way.
tmp = new NetEBShift(op_, lp, rp);
}
tmp->set_line(*this);
break; break;
case 'r': // >> case 'r': // >>
case 'R': // >>> case 'R': // >>>
tmp = new NetEBShift(op_, lp, rp); tmp = elaborate_expr_base_rshift_(des, lp, rp, expr_wid);
tmp->set_line(*this);
break; break;
case '^': case '^':
@ -271,11 +230,7 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des,
case '+': case '+':
case '-': case '-':
tmp = new NetEBAdd(op_, lp, rp, expr_wid==-2? true : false); tmp = elaborate_expr_base_add_(des, lp, rp, expr_wid);
if (expr_wid > 0 && (tmp->expr_type() == IVL_VT_BOOL
|| tmp->expr_type() == IVL_VT_LOGIC))
tmp->set_width(expr_wid);
tmp->set_line(*this);
break; break;
case 'E': /* === */ case 'E': /* === */
@ -323,6 +278,224 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des,
return tmp; return tmp;
} }
NetExpr* PEBinary::elaborate_expr_base_lshift_(Design*des,
NetExpr*lp, NetExpr*rp,
int expr_wid) const
{
NetExpr*tmp;
long use_wid = lp->expr_width();
if (expr_wid > 0)
use_wid = expr_wid;
if (use_wid == 0) {
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Oops, left expression width is not known, "
<< "so expression width is not known. Punt." << endl;
tmp = new NetEBShift(op_, lp, rp);
tmp->set_line(*this);
return tmp;
}
// If the left expression is constant, then there are some
// special cases we can work with. If the left expression is
// not constant, but the right expression is constant, then
// there are some other interesting cases. But if neither are
// constant, then there is the general case.
if (NetEConst*lpc = dynamic_cast<NetEConst*> (lp)) {
if (NetEConst*rpc = dynamic_cast<NetEConst*> (rp)) {
// Handle the super-special case that both
// operands are constants. Precalculate the
// entire value here.
verinum lpval = lpc->value();
unsigned shift = rpc->value().as_ulong();
verinum result = lpc->value() << shift;
// If the l-value has explicit size, or
// there is a context determined size, use that.
if (lpval.has_len() || expr_wid > 0) {
int use_len = lpval.len();
if (expr_wid > 0 && expr_wid > use_len)
use_len = expr_wid;
result = verinum(result, use_len);
}
tmp = new NetEConst(result);
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Precalculate " << *lpc << " << " << shift
<< " to constant " << *tmp
<< " (expr_wid=" << expr_wid << ")" << endl;
} else {
// Handle the special case that the left
// operand is constant. If it is unsized, we
// may have to expand it to an integer width.
verinum lpval = lpc->value();
if (lpval.len() < integer_width && !lpval.has_len()) {
lpval = verinum(lpval, integer_width);
lpc = new NetEConst(lpval);
lpc->set_line(*lp);
}
tmp = new NetEBShift(op_, lpc, rp);
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Adjust " << *this
<< " to this " << *tmp
<< " to allow for integer widths." << endl;
}
} else if (NetEConst*rpc = dynamic_cast<NetEConst*> (rp)) {
long shift = rpc->value().as_long();
long use_wid = lp->expr_width();
if (expr_wid > 0)
use_wid = expr_wid;
if (shift >= use_wid || (-shift) >= (long)lp->expr_width()) {
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Value left-shifted " << shift
<< " beyond width of " << use_wid
<< ". Elaborate as constant zero." << endl;
tmp = make_const_0(use_wid);
} else {
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Left shift expression by constant "
<< shift << " bits. (use_wid=" << use_wid << ")" << endl;
lp = pad_to_width(lp, use_wid);
tmp = new NetEBShift(op_, lp, rp);
}
} else {
// Left side is not constant, so handle it the
// default way.
if (expr_wid >= 0)
lp = pad_to_width(lp, expr_wid);
tmp = new NetEBShift(op_, lp, rp);
}
tmp->set_line(*this);
return tmp;
}
NetExpr* PEBinary::elaborate_expr_base_rshift_(Design*des,
NetExpr*lp, NetExpr*rp,
int expr_wid) const
{
NetExpr*tmp;
long use_wid = lp->expr_width();
if (expr_wid > 0)
use_wid = expr_wid;
if (use_wid == 0) {
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Oops, left expression width is not known, "
<< "so expression width is not known. Punt." << endl;
tmp = new NetEBShift(op_, lp, rp);
tmp->set_line(*this);
return tmp;
}
if (NetEConst*rpc = dynamic_cast<NetEConst*> (rp)) {
long shift = rpc->value().as_long();
// Detect the special cases that the shifted
// unsigned expression is completely shifted away to
// zero.
if ((op_=='r' || (lp->has_sign()==false))
&& shift >= (long)lp->expr_width()) {
// Special case that the value is unsigned
// shifted completely away.
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Value right-shifted " << shift
<< " beyond width of " << lp->expr_width()
<< ". Elaborate as constant zero." << endl;
tmp = make_const_0(use_wid);
tmp->set_line(*this);
return tmp;
}
if (shift >= (long)lp->expr_width()) {
// Signed right shift.
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Value signed-right-shifted " << shift
<< " beyond width of " << lp->expr_width()
<< ". Elaborate as replicated top bit." << endl;
tmp = new NetEConst(verinum(lp->expr_width()-1));
tmp->set_line(*this);
tmp = new NetESelect(lp, tmp, 1);
tmp->cast_signed(true);
tmp->set_line(*this);
tmp = pad_to_width(tmp, use_wid);
tmp->set_line(*this);
return tmp;
} else if (shift >= 0) {
// Signed right shift.
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Value signed-right-shifted " << shift
<< " beyond width of " << lp->expr_width()
<< "." << endl;
tmp = new NetEConst(verinum(shift));
tmp->set_line(*this);
long tmp_wid = lp->expr_width() - shift;
if (tmp_wid > use_wid)
tmp_wid = use_wid;
tmp = new NetESelect(lp, tmp, tmp_wid);
tmp->set_line(*this);
tmp->cast_signed(lp->has_sign() && op_=='R');
tmp = pad_to_width(tmp, use_wid);
tmp->set_line(*this);
return tmp;
} else if ((0-shift) >= use_wid) {
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
<< "Value signed-right-shifted " << shift
<< " beyond width of " << use_wid
<< "." << endl;
tmp = make_const_0(use_wid);
tmp->set_line(*this);
return tmp;
}
}
// Falback, handle the general case.
if (expr_wid > 0)
lp = pad_to_width(lp, expr_wid);
tmp = new NetEBShift(op_, lp, rp);
tmp->set_line(*this);
return tmp;
}
NetExpr* PEBinary::elaborate_expr_base_add_(Design*des,
NetExpr*lp, NetExpr*rp,
int expr_wid) const
{
NetExpr*tmp;
tmp = new NetEBAdd(op_, lp, rp, expr_wid==-2? true : false);
if (expr_wid > 0 && (tmp->expr_type() == IVL_VT_BOOL
|| tmp->expr_type() == IVL_VT_LOGIC))
tmp->set_width(expr_wid);
tmp->set_line(*this);
return tmp;
}
unsigned PEBComp::test_width(Design*, NetScope*,unsigned, unsigned, bool&) const unsigned PEBComp::test_width(Design*, NetScope*,unsigned, unsigned, bool&) const
{ {
return 1; return 1;
@ -376,6 +549,11 @@ unsigned PEBShift::test_width(Design*des, NetScope*scope,
// The right expression is self-determined and has no impact // The right expression is self-determined and has no impact
// on the expression size that is generated. // on the expression size that is generated.
if (wid_left < min)
wid_left = min;
if (wid_left < lval)
wid_left = lval;
return wid_left; return wid_left;
} }
@ -995,36 +1173,70 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope,
symbol_search(des, scope, path_, net, par, eve, ex1, ex2); symbol_search(des, scope, path_, net, par, eve, ex1, ex2);
if (net != 0) { // If there is a part/bit select expression, then process it
const name_component_t&name_tail = path_.back(); // here. This constrains the results no matter what kind the
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE; // name is.
if (!name_tail.index.empty())
use_sel = name_tail.index.back().sel;
unsigned use_width = net->vector_width(); const name_component_t&name_tail = path_.back();
switch (use_sel) { index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
case index_component_t::SEL_NONE: if (!name_tail.index.empty())
break; use_sel = name_tail.index.back().sel;
case index_component_t::SEL_PART:
{ long msb, lsb; unsigned use_width = UINT_MAX;
calculate_parts_(des, scope, msb, lsb); switch (use_sel) {
use_width = 1 + ((msb>lsb)? (msb-lsb) : (lsb-msb)); case index_component_t::SEL_NONE:
break; break;
} case index_component_t::SEL_PART:
case index_component_t::SEL_IDX_UP: { long msb, lsb;
case index_component_t::SEL_IDX_DO: calculate_parts_(des, scope, msb, lsb);
{ unsigned long tmp = 0; use_width = 1 + ((msb>lsb)? (msb-lsb) : (lsb-msb));
calculate_up_do_width_(des, scope, tmp); break;
use_width = tmp; }
break; case index_component_t::SEL_IDX_UP:
} case index_component_t::SEL_IDX_DO:
case index_component_t::SEL_BIT: { unsigned long tmp = 0;
use_width = 1; calculate_up_do_width_(des, scope, tmp);
break; use_width = tmp;
default: break;
ivl_assert(*this, 0); }
} case index_component_t::SEL_BIT:
use_width = 1;
break;
default:
ivl_assert(*this, 0);
}
if (use_width != UINT_MAX)
return use_width; return use_width;
// The width of a signal expression is the width of the signal.
if (net != 0)
return net->vector_width();
// The width of a parameter name is the width of the range for
// the parameter name, if a range is declared. Otherwise, the
// width is undefined.
if (par != 0) {
if (ex1) {
ivl_assert(*this, ex2);
const NetEConst*ex1_const = dynamic_cast<const NetEConst*> (ex1);
const NetEConst*ex2_const = dynamic_cast<const NetEConst*> (ex2);
ivl_assert(*this, ex1_const && ex2_const);
long msb = ex1_const->value().as_long();
long lsb = ex2_const->value().as_long();
if (msb >= lsb)
return msb - lsb + 1;
else
return lsb - msb + 1;
}
// This is a parameter. If it is sized (meaning it was
// declared with range expresions) then the range
// expressions would have been caught above. So if we
// got there there we know this is an unsized constant.
unsized_flag = true;
return par->expr_width();
} }
return min; return min;
@ -1123,6 +1335,22 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
} }
} }
if (error_implicit==false
&& sys_task_arg==false
&& path_.size()==1
&& scope->default_nettype() != NetNet::NONE) {
NetNet::Type nettype = scope->default_nettype();
net = new NetNet(scope, peek_tail_name(path_), nettype, 1);
net->data_type(IVL_VT_LOGIC);
net->set_line(*this);
if (warn_implicit) {
cerr << get_fileline() << ": warning: implicit "
"definition of wire " << scope_path(scope)
<< "." << peek_tail_name(path_) << "." << endl;
}
return elaborate_expr_net(des, scope, net, scope, sys_task_arg);
}
// At this point we've exhausted all the possibilities that // At this point we've exhausted all the possibilities that
// are not scopes. If this is not a system task argument, then // are not scopes. If this is not a system task argument, then
// it cannot be a scope name, so give up. // it cannot be a scope name, so give up.
@ -1943,7 +2171,7 @@ static bool test_ternary_operand_compat(ivl_variable_type_t l,
* parsed so I can presume that they exist, and call elaboration * parsed so I can presume that they exist, and call elaboration
* methods. If any elaboration fails, then give up and return 0. * methods. If any elaboration fails, then give up and return 0.
*/ */
NetETernary*PETernary::elaborate_expr(Design*des, NetScope*scope, NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope,
int expr_wid, bool) const int expr_wid, bool) const
{ {
assert(expr_); assert(expr_);
@ -1962,17 +2190,54 @@ NetETernary*PETernary::elaborate_expr(Design*des, NetScope*scope,
<< " and " << fal_wid << endl; << " and " << fal_wid << endl;
} }
NetExpr*con = expr_->elaborate_expr(des, scope, -1, false); // Elaborate and evaluate the condition expression. Note that
// it is always self-determined.
NetExpr*con = elab_and_eval(des, scope, expr_, -1);
if (con == 0) if (con == 0)
return 0; return 0;
NetExpr*tru = tru_->elaborate_expr(des, scope, expr_wid, false); /* Make sure the condition expression reduces to a single bit. */
con = condition_reduce(con);
// Verilog doesn't say that we must do short circuit
// evaluation of ternary expressions, but it doesn't disallow
// it. The disadvantage of doing this is that semantic errors
// in the unused clause will be missed, but people don't seem
// to mind, and do apreciate the optimization available here.
if (NetEConst*tmp = dynamic_cast<NetEConst*> (con)) {
verinum cval = tmp->value();
ivl_assert(*this, cval.len()==1);
// Condition is constant TRUE, so we only need the true claue.
if (cval.get(0) == verinum::V1) {
cerr << get_fileline() << ": debug: "
<< "Short-circuit elaborate TRUE clause of ternary."
<< endl;
NetExpr*tru = elab_and_eval(des, scope, tru_, expr_wid);
return pad_to_width(tru, expr_wid);
}
// Condition is constant FALSE, so we only need the
// false clause.
if (cval.get(0) == verinum::V0) {
cerr << get_fileline() << ": debug: "
<< "Short-circuit elaborate FALSE clause of ternary."
<< endl;
NetExpr*fal = elab_and_eval(des, scope, fal_, expr_wid);
return pad_to_width(fal, expr_wid);
}
// X and Z conditions need to blend both results, so we
// can't short-circuit.
}
NetExpr*tru = elab_and_eval(des, scope, tru_, expr_wid);
if (tru == 0) { if (tru == 0) {
delete con; delete con;
return 0; return 0;
} }
NetExpr*fal = fal_->elaborate_expr(des, scope, expr_wid, false); NetExpr*fal = elab_and_eval(des, scope, fal_, expr_wid);
if (fal == 0) { if (fal == 0) {
delete con; delete con;
delete tru; delete tru;
@ -1998,6 +2263,38 @@ NetETernary*PETernary::elaborate_expr(Design*des, NetScope*scope,
return res; return res;
} }
unsigned PEUnary::test_width(Design*des, NetScope*scope,
unsigned min, unsigned lval,
bool&unsized_flag) const
{
switch (op_) {
case '!':
case '&':
case '|': // Reduction OR
case '^': // Reduction XOR
case 'A': // Reduction NAND (~&)
case 'N': // Reduction NOR (~|)
case 'X': // Reduction NXOR (~^)
return 1;
}
unsigned test_wid = expr_->test_width(des, scope, min, lval, unsized_flag);
switch (op_) {
// For these operators, the act of padding to the
// minimum width can have an important impact on the
// calculation. So don't let the tested width be less
// then the tested width.
case '-':
case '+':
if (test_wid < min)
test_wid = min;
break;
}
return test_wid;
}
NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope,
int expr_wid, bool) const int expr_wid, bool) const
{ {
@ -2055,6 +2352,8 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope,
delete ip; delete ip;
} else { } else {
if (expr_wid > 0)
ip = pad_to_width(ip, expr_wid);
tmp = new NetEUnary(op_, ip); tmp = new NetEUnary(op_, ip);
tmp->set_line(*this); tmp->set_line(*this);
} }

View File

@ -355,7 +355,7 @@ static NetNet* compare_eq_constant(Design*des, NetScope*scope,
: verinum::V1, : verinum::V1,
1); 1);
NetEConst*ogate = new NetEConst(oval); NetEConst*ogate = new NetEConst(oval);
NetNet*osig = ogate->synthesize(des); NetNet*osig = ogate->synthesize(des, scope);
osig->data_type(lsig->data_type()); osig->data_type(lsig->data_type());
osig->set_line(*lsig); osig->set_line(*lsig);
osig->rise_time(rise); osig->rise_time(rise);
@ -484,7 +484,7 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
use of the situation, or 0 if it cannot. */ use of the situation, or 0 if it cannot. */
if (NetEConst*tmp = dynamic_cast<NetEConst*>(rexp)) { if (NetEConst*tmp = dynamic_cast<NetEConst*>(rexp)) {
lsig = lexp->synthesize(des); lsig = lexp->synthesize(des, scope);
if (lsig == 0) return 0; if (lsig == 0) return 0;
delete lexp; delete lexp;
lexp = 0; lexp = 0;
@ -492,7 +492,7 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
if (real_arg) { if (real_arg) {
verireal vrl(tmp->value().as_double()); verireal vrl(tmp->value().as_double());
NetECReal rlval(vrl); NetECReal rlval(vrl);
rsig = rlval.synthesize(des); rsig = rlval.synthesize(des, scope);
delete rexp; delete rexp;
rexp = 0; rexp = 0;
} else { } else {
@ -508,7 +508,7 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
if (NetEConst*tmp = dynamic_cast<NetEConst*>(lexp)) { if (NetEConst*tmp = dynamic_cast<NetEConst*>(lexp)) {
rsig = rexp->synthesize(des); rsig = rexp->synthesize(des, scope);
if (rsig == 0) return 0; if (rsig == 0) return 0;
delete rexp; delete rexp;
rexp = 0; rexp = 0;
@ -516,7 +516,7 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
if (real_arg) { if (real_arg) {
verireal vrl(tmp->value().as_double()); verireal vrl(tmp->value().as_double());
NetECReal rlval(vrl); NetECReal rlval(vrl);
lsig = rlval.synthesize(des); lsig = rlval.synthesize(des, scope);
delete lexp; delete lexp;
lexp = 0; lexp = 0;
} else { } else {
@ -531,13 +531,13 @@ NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope,
} }
if (lsig == 0) { if (lsig == 0) {
lsig = lexp->synthesize(des); lsig = lexp->synthesize(des, scope);
if (lsig == 0) return 0; if (lsig == 0) return 0;
delete lexp; delete lexp;
} }
if (rsig == 0) { if (rsig == 0) {
rsig = rexp->synthesize(des); rsig = rexp->synthesize(des, scope);
if (rsig == 0) return 0; if (rsig == 0) return 0;
delete rexp; delete rexp;
} }
@ -1737,14 +1737,14 @@ NetNet* PEIdent::elaborate_net_bitmux_(Design*des, NetScope*scope,
sel_expr = make_sub_expr(sig->lsb(), sel_expr); sel_expr = make_sub_expr(sig->lsb(), sel_expr);
eval_expr(sel_expr); eval_expr(sel_expr);
sel = sel_expr->synthesize(des); sel = sel_expr->synthesize(des, scope);
} else if (sig->lsb() != 0) { } else if (sig->lsb() != 0) {
NetExpr*sel_expr = index_tail.msb->elaborate_expr(des, scope, -1,false); NetExpr*sel_expr = index_tail.msb->elaborate_expr(des, scope, -1,false);
sel_expr = make_add_expr(sel_expr, - sig->lsb()); sel_expr = make_add_expr(sel_expr, - sig->lsb());
eval_expr(sel_expr); eval_expr(sel_expr);
sel = sel_expr->synthesize(des); sel = sel_expr->synthesize(des, scope);
} else { } else {
sel = index_tail.msb->elaborate_net(des, scope, 0, 0, 0, 0); sel = index_tail.msb->elaborate_net(des, scope, 0, 0, 0, 0);
@ -2188,7 +2188,7 @@ NetNet* PEIdent::elaborate_net_net_idx_up_(Design*des, NetScope*scope,
base = make_sub_expr(vwid-offset-wid, base); base = make_sub_expr(vwid-offset-wid, base);
} }
NetPartSelect*sel = new NetPartSelect(sig, base->synthesize(des), wid); NetPartSelect*sel = new NetPartSelect(sig, base->synthesize(des, scope), wid);
sel->set_line(*this); sel->set_line(*this);
des->add_node(sel); des->add_node(sel);
@ -2281,7 +2281,7 @@ NetNet* PEIdent::elaborate_net_array_(Design*des, NetScope*scope,
index_ex = make_add_expr(index_ex, 0-array_base); index_ex = make_add_expr(index_ex, 0-array_base);
} }
NetNet*index_net = index_ex->synthesize(des); NetNet*index_net = index_ex->synthesize(des, scope);
connect(mux->pin_Address(), index_net->pin(0)); connect(mux->pin_Address(), index_net->pin(0));
NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet*tmp = new NetNet(scope, scope->local_symbol(),
@ -3159,7 +3159,7 @@ NetNet* PETernary::elaborate_net(Design*des, NetScope*scope,
* on this for now. */ * on this for now. */
break; break;
} }
expr_sig = expr->synthesize(des); expr_sig = expr->synthesize(des, scope);
if (expr_sig == 0 || tru_sig == 0 || fal_sig == 0) return 0; if (expr_sig == 0 || tru_sig == 0 || fal_sig == 0) return 0;
@ -3355,7 +3355,7 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
drive0, drive1); drive0, drive1);
} }
NetNet* sub_sig = expr->synthesize(des); NetNet* sub_sig = expr->synthesize(des, scope);
if (sub_sig == 0) return 0; if (sub_sig == 0) return 0;
@ -3621,7 +3621,7 @@ NetNet* PEUnary::elab_net_unary_real_(Design*des, NetScope*scope,
<< *this << "."<<endl; << *this << "."<<endl;
} }
NetNet* sub_sig = expr->synthesize(des); NetNet* sub_sig = expr->synthesize(des, scope);
if (sub_sig == 0) return 0; if (sub_sig == 0) return 0;
delete expr; delete expr;

View File

@ -91,7 +91,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
return; return;
} }
assert(lval->pin_count() == 1); ivl_assert(*this, lval->pin_count() == 1);
if (debug_elaborate) { if (debug_elaborate) {
cerr << get_fileline() << ": debug: PGAssign: elaborated l-value" cerr << get_fileline() << ": debug: PGAssign: elaborated l-value"
@ -99,208 +99,75 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
<< ", type=" << lval->data_type() << endl; << ", type=" << lval->data_type() << endl;
} }
/* Handle the special case that the rval is simply an bool unsized_flag = false;
identifier. Get the rval as a NetNet, then use NetBUFZ unsigned use_width = pin(1)->test_width(des, scope, lval->vector_width(),
objects to connect it to the l-value. This is necessary to lval->vector_width(), unsized_flag);
direct drivers. This is how I attach strengths to the
assignment operation. */
if (const PEIdent*id = dynamic_cast<const PEIdent*>(pin(1))) {
NetNet*rid = id->elaborate_net(des, scope, lval->vector_width(),
0, 0, 0, Link::STRONG,
Link::STRONG);
if (rid == 0) {
des->errors += 1;
return;
}
/* Cast the right side when needed. */ if (debug_elaborate) {
if ((lval->data_type() == IVL_VT_REAL && cerr << get_fileline() << ": debug: PGAssign: r-value tested "
rid->data_type() != IVL_VT_REAL)) { << "width is " << use_width
rid = cast_to_real(des, scope, rid); << ", min=" << lval->vector_width()
} else if ((lval->data_type() != IVL_VT_REAL && << ", unsized_flag=" << (unsized_flag?"true":"false") << endl;
rid->data_type() == IVL_VT_REAL)) {
rid = cast_to_int(des, scope, rid, lval->vector_width());
}
ivl_assert(*this, rid);
if (rid->pin_count() != 1) {
cerr << get_fileline() << ": internal error: "
<< "Invalid elaborate_net results here:" << endl;
rid->dump_net(cerr, 4);
des->errors += 1;
return;
}
ivl_assert(*this, rid->pin_count() == 1);
/* If the right hand net is the same type as the left
side net (i.e., WIRE/WIRE) then it is enough to just
connect them together. Otherwise, put a bufz between
them to carry strengths from the rval.
While we are at it, handle the case where the r-value
is not as wide as the l-value by padding with a
constant-0. */
unsigned cnt = lval->vector_width();
if (rid->vector_width() < cnt)
cnt = rid->vector_width();
bool need_driver_flag = false;
/* If the device is linked to itself, a driver is
needed. Should I print a warning here? */
if (lval->pin(0) .is_linked (rid->pin(0)))
need_driver_flag = true;
/* If the nets are different type (i.e., reg vs. tri) then
a driver is needed. */
if (rid->type() != lval->type())
need_driver_flag = true;
/* If there is a delay, then I need a driver to carry
it. */
if (rise_time || fall_time || decay_time)
need_driver_flag = true;
/* If there is a strength to be carried, then I need a
driver to carry that strength. */
if (rid->pin(0).drive0() != drive0)
need_driver_flag = true;
if (rid->pin(0).drive1() != drive1)
need_driver_flag = true;
/* If the r-value is more narrow then the l-value, pad
it to the desired width. */
if (cnt < lval->vector_width()) {
if (lval->get_signed() && rid->get_signed()) {
unsigned use_width = lval->vector_width();
if (debug_elaborate)
cerr << get_fileline() << ": debug: PGassign "
<< "Generate sign-extend node." << endl;
rid = pad_to_width_signed(des, rid, use_width);
} else {
if (debug_elaborate)
cerr << get_fileline() << ": debug: PGAssign "
<< "Unsigned pad r-value from "
<< cnt << " bits to "
<< lval->vector_width() << " bits." << endl;
NetNet*tmp = pad_to_width(des, rid,
lval->vector_width());
rid = tmp;
}
} else if (cnt < rid->vector_width()) {
if (debug_elaborate)
cerr << get_fileline() << ": debug: PGAssign "
<< "Truncate r-value from "
<< cnt << " bits to "
<< lval->vector_width() << " bits." << endl;
NetNet*tmp = crop_to_width(des, rid, lval->vector_width());
rid = tmp;
}
if (! need_driver_flag) {
/* Don't need a driver, presumably because the
r-value already has the needed drivers. Just
hook things up. If the r-value is too narrow
for the l-value, then sign extend it or zero
extend it, whichever makes sense. */
if (debug_elaborate) {
cerr << get_fileline() << ": debug: PGAssign: "
<< "Connect lval directly to "
<< id->path() << endl;
}
connect(lval->pin(0), rid->pin(0));
} else {
/* Do need a driver. Use BUFZ objects to carry the
strength and delays. */
if (debug_elaborate) {
cerr << get_fileline() << ": debug: PGAssign: "
<< "Connect lval to " << id->path()
<< " through bufz. delay=(";
if (rise_time)
cerr << *rise_time << ":";
else
cerr << "<none>:";
if (fall_time)
cerr << *fall_time << ":";
else
cerr << "<none>:";
if (decay_time)
cerr << *decay_time;
else
cerr << "<none>";
cerr << ")" << endl;
}
NetBUFZ*dev = new NetBUFZ(scope, scope->local_symbol(),
rid->vector_width());
connect(lval->pin(0), dev->pin(0));
connect(rid->pin(0), dev->pin(1));
dev->rise_time(rise_time);
dev->fall_time(fall_time);
dev->decay_time(decay_time);
dev->pin(0).drive0(drive0);
dev->pin(0).drive1(drive1);
des->add_node(dev);
}
return;
} }
/* Elaborate the r-value. Account for the initial decays, int expr_wid = unsized_flag? -1 : use_width;
which are going to be attached to the last gate before the NetExpr*rval_expr = elab_and_eval(des, scope, pin(1),
generated NetNet. */ expr_wid, lval->vector_width());
NetNet*rval = pin(1)->elaborate_net(des, scope,
lval->vector_width(), if (rval_expr == 0) {
0, 0, 0,
drive0, drive1);
if (rval == 0) {
cerr << get_fileline() << ": error: Unable to elaborate r-value: " cerr << get_fileline() << ": error: Unable to elaborate r-value: "
<< *pin(1) << endl; << *pin(1) << endl;
des->errors += 1; des->errors += 1;
return; return;
} }
NetNet*rval = rval_expr->synthesize(des, scope);
if (rval == 0) {
cerr << get_fileline() << ": internal error: "
<< "Failed to synthesize expression: " << *rval_expr << endl;
des->errors += 1;
return;
}
if (debug_elaborate) { if (debug_elaborate) {
cerr << get_fileline() << ": debug: PGAssign: elaborated r-value" cerr << get_fileline() << ": debug: PGAssign: elaborated r-value"
<< " width="<<rval->vector_width() << " width="<< rval->vector_width()
<< ", type="<< rval->data_type() << endl; << ", type="<< rval->data_type()
<< ", expr=" << *rval_expr << endl;
} }
assert(lval && rval); assert(lval && rval);
assert(rval->pin_count() == 1); assert(rval->pin_count() == 1);
// Detect the case that the rvalue-expression is a simple
// expression. In this case, we will need to create a driver
// (later) to carry strengths.
bool need_driver_flag = false;
if (dynamic_cast<NetESignal*>(rval_expr))
need_driver_flag = true;
/* Cast the right side when needed. */ /* Cast the right side when needed. */
if ((lval->data_type() == IVL_VT_REAL && if ((lval->data_type() == IVL_VT_REAL &&
rval->data_type() != IVL_VT_REAL)) { rval->data_type() != IVL_VT_REAL)) {
rval = cast_to_real(des, scope, rval); rval = cast_to_real(des, scope, rval);
need_driver_flag = false;
} else if ((lval->data_type() != IVL_VT_REAL && } else if ((lval->data_type() != IVL_VT_REAL &&
rval->data_type() == IVL_VT_REAL)) { rval->data_type() == IVL_VT_REAL)) {
rval = cast_to_int(des, scope, rval, lval->vector_width()); rval = cast_to_int(des, scope, rval, lval->vector_width());
need_driver_flag = false;
} }
/* If the r-value insists on being smaller then the l-value /* If the r-value insists on being smaller then the l-value
(perhaps it is explicitly sized) the pad it out to be the (perhaps it is explicitly sized) the pad it out to be the
right width so that something is connected to all the bits right width so that something is connected to all the bits
of the l-value. */ of the l-value. */
if (lval->vector_width() > rval->vector_width()) if (lval->vector_width() > rval->vector_width()) {
rval = pad_to_width(des, rval, lval->vector_width()); if (rval->get_signed())
rval = pad_to_width_signed(des, rval, lval->vector_width());
else
rval = pad_to_width(des, rval, lval->vector_width());
}
/* If, on the other hand, the r-value insists on being /* If, on the other hand, the r-value insists on being
LARGER then the l-value, use a part select to chop it down LARGER then the l-value, use a part select to chop it down
@ -313,17 +180,40 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::TRI, lval->vector_width()); NetNet::TRI, lval->vector_width());
osig->set_line(*this); osig->set_line(*this);
osig->local_flag(true);
osig->data_type(rval->data_type()); osig->data_type(rval->data_type());
connect(osig->pin(0), tmp->pin(0)); connect(osig->pin(0), tmp->pin(0));
rval = osig; rval = osig;
need_driver_flag = false;
} }
/* If there is a rise/fall/decay time, then attach that delay if (need_driver_flag) {
to the drivers for this net. */ NetBUFZ*driver = new NetBUFZ(scope, scope->local_symbol(),
if (rise_time || fall_time || decay_time) { rval->vector_width());
rval->pin(0).drivers_delays(rise_time, fall_time, decay_time); driver->set_line(*this);
des->add_node(driver);
connect(rval->pin(0), driver->pin(1));
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, rval->vector_width());
tmp->set_line(*this);
tmp->data_type(rval->data_type());
tmp->local_flag(true);
connect(driver->pin(0), tmp->pin(0));
rval = tmp;
} }
/* Set the drive and delays for the r-val. */
if (drive0 != Link::STRONG || drive1 != Link::STRONG)
rval->pin(0).drivers_drive(drive0, drive1);
if (rise_time || fall_time || decay_time)
rval->pin(0).drivers_delays(rise_time, fall_time, decay_time);
connect(lval->pin(0), rval->pin(0)); connect(lval->pin(0), rval->pin(0));
if (lval->local_flag()) if (lval->local_flag())
@ -1705,6 +1595,29 @@ NetAssign_* PAssign_::elaborate_lval(Design*des, NetScope*scope) const
return lval_->elaborate_lval(des, scope, false); return lval_->elaborate_lval(des, scope, false);
} }
NetExpr* PAssign_::elaborate_rval_(Design*des, NetScope*scope,
unsigned lv_width) const
{
ivl_assert(*this, rval_);
/* Find out what the r-value width is going to be. We guess it
will be the l-value width, but it may turn out to be
something else based on self-determined widths inside. */
unsigned use_width = lv_width;
bool unsized_flag = false;
unsigned tmp_width = rval()->test_width(des, scope, use_width, use_width, unsized_flag);
if (tmp_width > use_width)
use_width = tmp_width;
/* Now elaborate to the expected width. Pass the lwidth to
prune any constant result to fit with the lvalue at hand. */
NetExpr*rv = elab_and_eval(des, scope, rval_, use_width, lv_width);
if (rv == 0) return 0;
return rv;
}
/* /*
* This function elaborates delay expressions. This is a little * This function elaborates delay expressions. This is a little
* different from normal elaboration because the result may need to be * different from normal elaboration because the result may need to be
@ -1786,20 +1699,8 @@ NetProc* PAssign::elaborate(Design*des, NetScope*scope) const
delay = elaborate_delay_expr(delay_, des, scope); delay = elaborate_delay_expr(delay_, des, scope);
assert(rval());
/* Elaborate the r-value expression, then try to evaluate it. */ /* Elaborate the r-value expression, then try to evaluate it. */
NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv));
/* Find out what the r-value width is going to be. We guess it
will be the l-value width, but it may turn out to be
something else based on self-determined widths inside. */
unsigned use_width = lv->lwidth();
bool unsized_flag = false;
use_width = rval()->test_width(des, scope, use_width, use_width, unsized_flag);
/* Now elaborate to the expected width. Pass the lwidth to
prune any constant result to fit with the lvalue at hand. */
NetExpr*rv = elab_and_eval(des, scope, rval(), use_width, lv->lwidth());
if (rv == 0) return 0; if (rv == 0) return 0;
assert(rv); assert(rv);
@ -1964,12 +1865,7 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const
NetAssign_*lv = elaborate_lval(des, scope); NetAssign_*lv = elaborate_lval(des, scope);
if (lv == 0) return 0; if (lv == 0) return 0;
assert(rval()); NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv));
/* Elaborate and precalculate the r-value. */
NetExpr*rv = elab_and_eval(des, scope, rval(), count_lval_width(lv));
if (rv == 0)
return 0;
/* Handle the (common) case that the r-value is a vector. This /* Handle the (common) case that the r-value is a vector. This
includes just about everything but reals. In this case, we includes just about everything but reals. In this case, we
@ -3515,7 +3411,7 @@ void PSpecPath::elaborate(Design*des, NetScope*scope) const
// FIXME: Look for constant expressions here? // FIXME: Look for constant expressions here?
// Get a net form. // Get a net form.
condit_sig = tmp->synthesize(des); condit_sig = tmp->synthesize(des, scope);
ivl_assert(*condition, condit_sig); ivl_assert(*condition, condit_sig);
} }
@ -3658,6 +3554,7 @@ static void elaborate_tasks(Design*des, NetScope*scope,
bool Module::elaborate(Design*des, NetScope*scope) const bool Module::elaborate(Design*des, NetScope*scope) const
{ {
bool result_flag = true; bool result_flag = true;
error_implicit = true;
if (gn_specify_blocks_flag) { if (gn_specify_blocks_flag) {
// Elaborate specparams // Elaborate specparams
@ -3722,6 +3619,7 @@ bool Module::elaborate(Design*des, NetScope*scope) const
// complex. // complex.
const list<PGate*>&gl = get_gates(); const list<PGate*>&gl = get_gates();
error_implicit = false;
for (list<PGate*>::const_iterator gt = gl.begin() for (list<PGate*>::const_iterator gt = gl.begin()
; gt != gl.end() ; gt != gl.end()
; gt ++ ) { ; gt ++ ) {
@ -3729,6 +3627,8 @@ bool Module::elaborate(Design*des, NetScope*scope) const
(*gt)->elaborate(des, scope); (*gt)->elaborate(des, scope);
} }
error_implicit = true;
// Elaborate the behaviors, making processes out of them. This // Elaborate the behaviors, making processes out of them. This
// involves scanning the PProcess* list, creating a NetProcTop // involves scanning the PProcess* list, creating a NetProcTop
// for each process. // for each process.

View File

@ -528,6 +528,13 @@ NetEConst* NetEBComp::eval_gteq_()
} }
} }
/*
* Evaluate <A>==<B> or <A>!=<B>. The equality operator checks all the
* bits and returns true(false) if there are any bits in the vector
* that are defined (0 or 1) and different. If all the defined bits
* are equal, but there are are x/z bits, then the situation is
* ambiguous so the result is x.
*/
NetEConst* NetEBComp::eval_eqeq_real_(NetExpr*le, NetExpr*ri, bool ne_flag) NetEConst* NetEBComp::eval_eqeq_real_(NetExpr*le, NetExpr*ri, bool ne_flag)
{ {
NetEConst*vtmp; NetEConst*vtmp;
@ -606,11 +613,14 @@ NetEConst* NetEBComp::eval_eqeq_(bool ne_flag)
for (unsigned idx = 0 ; idx < top ; idx += 1) { for (unsigned idx = 0 ; idx < top ; idx += 1) {
bool x_bit_present = false;
switch (lv.get(idx)) { switch (lv.get(idx)) {
case verinum::Vx: case verinum::Vx:
case verinum::Vz: case verinum::Vz:
res = verinum::Vx; res = verinum::Vx;
x_bit_present = true;
break; break;
default: default:
@ -622,17 +632,20 @@ NetEConst* NetEBComp::eval_eqeq_(bool ne_flag)
case verinum::Vx: case verinum::Vx:
case verinum::Vz: case verinum::Vz:
res = verinum::Vx; res = verinum::Vx;
x_bit_present = true;
break; break;
default: default:
break; break;
} }
if (res == verinum::Vx) if (x_bit_present)
break; continue;
if (rv.get(idx) != lv.get(idx)) if (rv.get(idx) != lv.get(idx)) {
res = ne_res; res = ne_res;
break;
}
} }
if (res != verinum::Vx) { if (res != verinum::Vx) {

View File

@ -26,14 +26,14 @@
# include "netmisc.h" # include "netmisc.h"
# include "ivl_assert.h" # include "ivl_assert.h"
NetNet* convert_to_real_const(Design*des, NetExpr*expr, NetExpr*obj) static NetNet* convert_to_real_const(Design*des, NetScope*scope, NetExpr*expr, NetExpr*obj)
{ {
NetNet* sig; NetNet* sig;
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) { if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) {
verireal vrl(tmp->value().as_double()); verireal vrl(tmp->value().as_double());
NetECReal rlval(vrl); NetECReal rlval(vrl);
sig = rlval.synthesize(des); sig = rlval.synthesize(des, scope);
} else { } else {
cerr << obj->get_fileline() << ": sorry: Cannot convert " cerr << obj->get_fileline() << ": sorry: Cannot convert "
"bit based value (" << *expr << ") to real." << endl; "bit based value (" << *expr << ") to real." << endl;
@ -45,9 +45,10 @@ NetNet* convert_to_real_const(Design*des, NetExpr*expr, NetExpr*obj)
} }
/* Note that lsig, rsig and real_args are references. */ /* Note that lsig, rsig and real_args are references. */
bool process_binary_args(Design*des, NetExpr*left, NetExpr*right, static bool process_binary_args(Design*des, NetScope*scope,
NetNet*&lsig, NetNet*&rsig, bool&real_args, NetExpr*left, NetExpr*right,
NetExpr*obj) NetNet*&lsig, NetNet*&rsig, bool&real_args,
NetExpr*obj)
{ {
if (left->expr_type() == IVL_VT_REAL || if (left->expr_type() == IVL_VT_REAL ||
right->expr_type() == IVL_VT_REAL) { right->expr_type() == IVL_VT_REAL) {
@ -56,20 +57,20 @@ bool process_binary_args(Design*des, NetExpr*left, NetExpr*right,
/* Currently we will have a runtime assert if both expressions /* Currently we will have a runtime assert if both expressions
are not real, though we can convert constants. */ are not real, though we can convert constants. */
if (left->expr_type() == IVL_VT_REAL) { if (left->expr_type() == IVL_VT_REAL) {
lsig = left->synthesize(des); lsig = left->synthesize(des, scope);
} else { } else {
lsig = convert_to_real_const(des, left, obj); lsig = convert_to_real_const(des, scope, left, obj);
} }
if (right->expr_type() == IVL_VT_REAL) { if (right->expr_type() == IVL_VT_REAL) {
rsig = right->synthesize(des); rsig = right->synthesize(des, scope);
} else { } else {
rsig = convert_to_real_const(des, right, obj); rsig = convert_to_real_const(des, scope, right, obj);
} }
} else { } else {
real_args = false; real_args = false;
lsig = left->synthesize(des); lsig = left->synthesize(des, scope);
rsig = right->synthesize(des); rsig = right->synthesize(des, scope);
} }
@ -77,7 +78,7 @@ bool process_binary_args(Design*des, NetExpr*left, NetExpr*right,
else return false; else return false;
} }
NetNet* NetExpr::synthesize(Design*des) NetNet* NetExpr::synthesize(Design*des, NetScope*scope)
{ {
cerr << get_fileline() << ": internal error: cannot synthesize expression: " cerr << get_fileline() << ": internal error: cannot synthesize expression: "
<< *this << endl; << *this << endl;
@ -88,13 +89,13 @@ NetNet* NetExpr::synthesize(Design*des)
/* /*
* Make an LPM_ADD_SUB device from addition operators. * Make an LPM_ADD_SUB device from addition operators.
*/ */
NetNet* NetEBAdd::synthesize(Design*des) NetNet* NetEBAdd::synthesize(Design*des, NetScope*scope)
{ {
assert((op()=='+') || (op()=='-')); ivl_assert(*this, (op()=='+') || (op()=='-'));
NetNet *lsig=0, *rsig=0; NetNet *lsig=0, *rsig=0;
bool real_args=false; bool real_args=false;
if (process_binary_args(des, left_, right_, lsig, rsig, if (process_binary_args(des, scope, left_, right_, lsig, rsig,
real_args, this)) { real_args, this)) {
return 0; return 0;
} }
@ -138,10 +139,10 @@ NetNet* NetEBAdd::synthesize(Design*des)
* signals, then just connect a single gate to each bit of the vector * signals, then just connect a single gate to each bit of the vector
* of the expression. * of the expression.
*/ */
NetNet* NetEBBits::synthesize(Design*des) NetNet* NetEBBits::synthesize(Design*des, NetScope*scope)
{ {
NetNet*lsig = left_->synthesize(des); NetNet*lsig = left_->synthesize(des, scope);
NetNet*rsig = right_->synthesize(des); NetNet*rsig = right_->synthesize(des, scope);
if (lsig == 0 || rsig == 0) return 0; if (lsig == 0 || rsig == 0) return 0;
@ -154,9 +155,6 @@ NetNet* NetEBBits::synthesize(Design*des)
return 0; return 0;
} }
NetScope*scope = lsig->scope();
assert(scope);
unsigned width = lsig->vector_width(); unsigned width = lsig->vector_width();
if (rsig->vector_width() > width) width = rsig->vector_width(); if (rsig->vector_width() > width) width = rsig->vector_width();
@ -205,13 +203,13 @@ NetNet* NetEBBits::synthesize(Design*des)
return osig; return osig;
} }
NetNet* NetEBComp::synthesize(Design*des) NetNet* NetEBComp::synthesize(Design*des, NetScope*scope)
{ {
NetNet *lsig=0, *rsig=0; NetNet *lsig=0, *rsig=0;
unsigned width; unsigned width;
bool real_args=false; bool real_args=false;
if (process_binary_args(des, left_, right_, lsig, rsig, if (process_binary_args(des, scope, left_, right_, lsig, rsig,
real_args, this)) { real_args, this)) {
return 0; return 0;
} }
@ -222,13 +220,16 @@ NetNet* NetEBComp::synthesize(Design*des)
width = lsig->vector_width(); width = lsig->vector_width();
if (rsig->vector_width() > width) width = rsig->vector_width(); if (rsig->vector_width() > width) width = rsig->vector_width();
lsig = pad_to_width(des, lsig, width); if (lsig->get_signed())
rsig = pad_to_width(des, rsig, width); 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);
} }
NetScope*scope = lsig->scope();
assert(scope);
NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, 1); NetNet::IMPLICIT, 1);
osig->set_line(*this); osig->set_line(*this);
@ -236,10 +237,30 @@ NetNet* NetEBComp::synthesize(Design*des)
osig->data_type(IVL_VT_LOGIC); osig->data_type(IVL_VT_LOGIC);
bool signed_compare = lsig->get_signed() && rsig->get_signed(); 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 /* Handle the special case of a single bit equality
operation. Make an XNOR gate instead of a comparator. */ 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(), NetLogic*gate = new NetLogic(scope, scope->local_symbol(),
3, NetLogic::XNOR, 1); 3, NetLogic::XNOR, 1);
gate->set_line(*this); gate->set_line(*this);
@ -253,7 +274,7 @@ NetNet* NetEBComp::synthesize(Design*des)
/* Handle the special case of a single bit inequality /* Handle the special case of a single bit inequality
operation. This is similar to single bit equality, but uses operation. This is similar to single bit equality, but uses
an XOR instead of an XNOR gate. */ 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(), NetLogic*gate = new NetLogic(scope, scope->local_symbol(),
3, NetLogic::XOR, 1); 3, NetLogic::XOR, 1);
gate->set_line(*this); gate->set_line(*this);
@ -321,12 +342,12 @@ NetNet* NetEBComp::synthesize(Design*des)
return osig; return osig;
} }
NetNet* NetEBPow::synthesize(Design*des) NetNet* NetEBPow::synthesize(Design*des, NetScope*scope)
{ {
NetNet *lsig=0, *rsig=0; NetNet *lsig=0, *rsig=0;
unsigned width; unsigned width;
bool real_args=false; bool real_args=false;
if (process_binary_args(des, left_, right_, lsig, rsig, if (process_binary_args(des, scope, left_, right_, lsig, rsig,
real_args, this)) { real_args, this)) {
return 0; return 0;
} }
@ -334,9 +355,6 @@ NetNet* NetEBPow::synthesize(Design*des)
if (real_args) width = 1; if (real_args) width = 1;
else width = expr_width(); else width = expr_width();
NetScope*scope = lsig->scope();
assert(scope);
NetPow*powr = new NetPow(scope, scope->local_symbol(), width, NetPow*powr = new NetPow(scope, scope->local_symbol(), width,
lsig->vector_width(), lsig->vector_width(),
rsig->vector_width()); rsig->vector_width());
@ -359,12 +377,12 @@ NetNet* NetEBPow::synthesize(Design*des)
return osig; return osig;
} }
NetNet* NetEBMult::synthesize(Design*des) NetNet* NetEBMult::synthesize(Design*des, NetScope*scope)
{ {
NetNet *lsig=0, *rsig=0; NetNet *lsig=0, *rsig=0;
unsigned width; unsigned width;
bool real_args=false; bool real_args=false;
if (process_binary_args(des, left_, right_, lsig, rsig, if (process_binary_args(des, scope, left_, right_, lsig, rsig,
real_args, this)) { real_args, this)) {
return 0; return 0;
} }
@ -372,9 +390,6 @@ NetNet* NetEBMult::synthesize(Design*des)
if (real_args) width = 1; if (real_args) width = 1;
else width = expr_width(); else width = expr_width();
NetScope*scope = lsig->scope();
assert(scope);
NetMult*mult = new NetMult(scope, scope->local_symbol(), NetMult*mult = new NetMult(scope, scope->local_symbol(),
width, width,
lsig->vector_width(), lsig->vector_width(),
@ -398,12 +413,12 @@ NetNet* NetEBMult::synthesize(Design*des)
return osig; return osig;
} }
NetNet* NetEBDiv::synthesize(Design*des) NetNet* NetEBDiv::synthesize(Design*des, NetScope*scope)
{ {
NetNet *lsig=0, *rsig=0; NetNet *lsig=0, *rsig=0;
unsigned width; unsigned width;
bool real_args=false; bool real_args=false;
if (process_binary_args(des, left_, right_, lsig, rsig, if (process_binary_args(des, scope, left_, right_, lsig, rsig,
real_args, this)) { real_args, this)) {
return 0; return 0;
} }
@ -411,12 +426,11 @@ NetNet* NetEBDiv::synthesize(Design*des)
if (real_args) width = 1; if (real_args) width = 1;
else width = expr_width(); else width = expr_width();
NetScope*scope = lsig->scope();
NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, width); NetNet::IMPLICIT, width);
osig->set_line(*this); osig->set_line(*this);
osig->data_type(lsig->data_type()); osig->data_type(lsig->data_type());
osig->set_signed(has_sign());
osig->local_flag(true); osig->local_flag(true);
switch (op()) { switch (op()) {
@ -427,6 +441,7 @@ NetNet* NetEBDiv::synthesize(Design*des)
lsig->vector_width(), lsig->vector_width(),
rsig->vector_width()); rsig->vector_width());
div->set_line(*this); div->set_line(*this);
div->set_signed(has_sign());
des->add_node(div); des->add_node(div);
connect(div->pin_DataA(), lsig->pin(0)); connect(div->pin_DataA(), lsig->pin(0));
@ -471,10 +486,10 @@ NetNet* NetEBDiv::synthesize(Design*des)
return osig; return osig;
} }
NetNet* NetEBLogic::synthesize(Design*des) NetNet* NetEBLogic::synthesize(Design*des, NetScope*scope)
{ {
NetNet*lsig = left_->synthesize(des); NetNet*lsig = left_->synthesize(des, scope);
NetNet*rsig = right_->synthesize(des); NetNet*rsig = right_->synthesize(des, scope);
if (lsig == 0 || rsig == 0) return 0; if (lsig == 0 || rsig == 0) return 0;
@ -487,9 +502,6 @@ NetNet* NetEBLogic::synthesize(Design*des)
return 0; return 0;
} }
NetScope*scope = lsig->scope();
assert(scope);
NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, 1); NetNet::IMPLICIT, 1);
osig->data_type(expr_type()); osig->data_type(expr_type());
@ -551,11 +563,11 @@ NetNet* NetEBLogic::synthesize(Design*des)
return osig; return osig;
} }
NetNet* NetEBShift::synthesize(Design*des) NetNet* NetEBShift::synthesize(Design*des, NetScope*scope)
{ {
eval_expr(right_); eval_expr(right_);
NetNet*lsig = left_->synthesize(des); NetNet*lsig = left_->synthesize(des, scope);
if (lsig == 0) return 0; if (lsig == 0) return 0;
@ -568,10 +580,8 @@ NetNet* NetEBShift::synthesize(Design*des)
return 0; return 0;
} }
bool right_flag = op_ == 'r' || op_ == 'R'; const bool right_flag = op_ == 'r' || op_ == 'R';
bool signed_flag = op_ == 'R'; const bool signed_flag = op_ == 'R';
NetScope*scope = lsig->scope();
/* Detect the special case where the shift amount is /* Detect the special case where the shift amount is
constant. Evaluate the shift amount, and simply reconnect constant. Evaluate the shift amount, and simply reconnect
@ -580,7 +590,7 @@ NetNet* NetEBShift::synthesize(Design*des)
verinum shift_v = rcon->value(); verinum shift_v = rcon->value();
long shift = shift_v.as_long(); long shift = shift_v.as_long();
if (op() == 'r') if (right_flag)
shift = 0-shift; shift = 0-shift;
if (shift == 0) if (shift == 0)
@ -593,34 +603,13 @@ NetNet* NetEBShift::synthesize(Design*des)
// ushift is the amount of pad created by the shift. // ushift is the amount of pad created by the shift.
unsigned long ushift = shift>=0? shift : -shift; unsigned long ushift = shift>=0? shift : -shift;
if (ushift > osig->vector_width()) ivl_assert(*this, ushift < osig->vector_width());
ushift = osig->vector_width();
// part_width is the bits of the vector that survive the shift. // part_width is the bits of the vector that survive the shift.
unsigned long part_width = osig->vector_width() - ushift; unsigned long part_width = osig->vector_width() - ushift;
verinum znum (verinum::V0, ushift, true); // Create a part select to reduce the width of the lsig
NetConst*zcon = new NetConst(scope, scope->local_symbol(), // to the amount left by the shift.
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. */
NetPartSelect*psel = new NetPartSelect(lsig, shift<0? ushift : 0, NetPartSelect*psel = new NetPartSelect(lsig, shift<0? ushift : 0,
part_width, part_width,
NetPartSelect::VP); NetPartSelect::VP);
@ -633,6 +622,34 @@ NetNet* NetEBShift::synthesize(Design*des)
psig->set_line(*this); psig->set_line(*this);
connect(psig->pin(0), psel->pin(0)); 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(), NetConcat*ccat = new NetConcat(scope, scope->local_symbol(),
osig->vector_width(), 2); osig->vector_width(), 2);
ccat->set_line(*this); ccat->set_line(*this);
@ -652,7 +669,7 @@ NetNet* NetEBShift::synthesize(Design*des)
return osig; return osig;
} }
NetNet*rsig = right_->synthesize(des); NetNet*rsig = right_->synthesize(des, scope);
if (rsig == 0) return 0; if (rsig == 0) return 0;
@ -678,13 +695,13 @@ NetNet* NetEBShift::synthesize(Design*des)
return osig; return osig;
} }
NetNet* NetEConcat::synthesize(Design*des) NetNet* NetEConcat::synthesize(Design*des, NetScope*scope)
{ {
/* First, synthesize the operands. */ /* First, synthesize the operands. */
NetNet**tmp = new NetNet*[parms_.count()]; NetNet**tmp = new NetNet*[parms_.count()];
bool flag = true; bool flag = true;
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) { for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
tmp[idx] = parms_[idx]->synthesize(des); tmp[idx] = parms_[idx]->synthesize(des, scope);
if (tmp[idx] == 0) if (tmp[idx] == 0)
flag = false; flag = false;
} }
@ -692,9 +709,7 @@ NetNet* NetEConcat::synthesize(Design*des)
if (flag == false) if (flag == false)
return 0; return 0;
assert(tmp[0]); ivl_assert(*this, tmp[0]);
NetScope*scope = tmp[0]->scope();
assert(scope);
/* Make a NetNet object to carry the output vector. */ /* Make a NetNet object to carry the output vector. */
perm_string path = scope->local_symbol(); perm_string path = scope->local_symbol();
@ -712,7 +727,9 @@ NetNet* NetEConcat::synthesize(Design*des)
unsigned cur_pin = 1; unsigned cur_pin = 1;
for (unsigned rpt = 0; rpt < repeat(); rpt += 1) { for (unsigned rpt = 0; rpt < repeat(); rpt += 1) {
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 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; cur_pin += 1;
} }
} }
@ -721,11 +738,8 @@ NetNet* NetEConcat::synthesize(Design*des)
return osig; return osig;
} }
NetNet* NetEConst::synthesize(Design*des) NetNet* NetEConst::synthesize(Design*des, NetScope*scope)
{ {
NetScope*scope = des->find_root_scope();
assert(scope);
perm_string path = scope->local_symbol(); perm_string path = scope->local_symbol();
unsigned width=expr_width(); unsigned width=expr_width();
@ -743,11 +757,8 @@ NetNet* NetEConst::synthesize(Design*des)
/* /*
* Create a NetLiteral object to represent real valued constants. * Create a NetLiteral object to represent real valued constants.
*/ */
NetNet* NetECReal::synthesize(Design*des) NetNet* NetECReal::synthesize(Design*des, NetScope*scope)
{ {
NetScope*scope = des->find_root_scope();
assert(scope);
perm_string path = scope->local_symbol(); perm_string path = scope->local_symbol();
NetNet*osig = new NetNet(scope, path, NetNet::WIRE, 1); NetNet*osig = new NetNet(scope, path, NetNet::WIRE, 1);
@ -768,9 +779,9 @@ NetNet* NetECReal::synthesize(Design*des)
* The bitwise unary logic operator (there is only one) is turned * The bitwise unary logic operator (there is only one) is turned
* into discrete gates just as easily as the binary ones above. * into discrete gates just as easily as the binary ones above.
*/ */
NetNet* NetEUBits::synthesize(Design*des) NetNet* NetEUBits::synthesize(Design*des, NetScope*scope)
{ {
NetNet*isig = expr_->synthesize(des); NetNet*isig = expr_->synthesize(des, scope);
if (isig == 0) return 0; if (isig == 0) return 0;
@ -782,9 +793,6 @@ NetNet* NetEUBits::synthesize(Design*des)
return 0; return 0;
} }
NetScope*scope = isig->scope();
assert(scope);
unsigned width = isig->vector_width(); unsigned width = isig->vector_width();
NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, width); NetNet::IMPLICIT, width);
@ -810,9 +818,46 @@ NetNet* NetEUBits::synthesize(Design*des)
return osig; return osig;
} }
NetNet* NetEUReduce::synthesize(Design*des) NetNet* NetEUnary::synthesize(Design*des, NetScope*scope)
{ {
NetNet*isig = expr_->synthesize(des); if (op_ == '+')
return expr_->synthesize(des, scope);
if (op_ == '-') {
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;
}
cerr << get_fileline() << ": iternal error: "
<< "NetEUnary::synthesize cannot handle op_=" << op_ << endl;
des->errors += 1;
return expr_->synthesize(des, scope);
}
NetNet* NetEUReduce::synthesize(Design*des, NetScope*scope)
{
NetNet*isig = expr_->synthesize(des, scope);
if (isig == 0) return 0; if (isig == 0) return 0;
@ -824,9 +869,6 @@ NetNet* NetEUReduce::synthesize(Design*des)
return 0; return 0;
} }
NetScope*scope = isig->scope();
assert(scope);
NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, 1); NetNet::IMPLICIT, 1);
osig->data_type(expr_type()); osig->data_type(expr_type());
@ -849,7 +891,7 @@ NetNet* NetEUReduce::synthesize(Design*des)
rtype = NetUReduce::XOR; rtype = NetUReduce::XOR;
break; break;
case 'A': case 'A':
rtype = NetUReduce::XNOR; rtype = NetUReduce::NAND;
break; break;
case 'X': case 'X':
rtype = NetUReduce::XNOR; rtype = NetUReduce::XNOR;
@ -871,22 +913,101 @@ NetNet* NetEUReduce::synthesize(Design*des)
return osig; return osig;
} }
NetNet* NetESelect::synthesize(Design *des) /*
* 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)
{ {
NetNet*sub = expr_->synthesize(des); NetNet*sub = expr_->synthesize(des, scope);
if (sub == 0) return 0; if (sub == 0) return 0;
NetScope*scope = sub->scope();
NetNet*off = 0; 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 // This handles the case that the NetESelect exists to do an
// actual part/bit select. Generate a NetPartSelect object to // actual part/bit select. Generate a NetPartSelect object to
// do the work, and replace "sub" with the selected output. // do the work, and replace "sub" with the selected output.
if (base_ != 0) { if (base_ != 0) {
off = base_->synthesize(des); off = base_->synthesize(des, scope);
NetPartSelect*sel = new NetPartSelect(sub, off, expr_width()); NetPartSelect*sel = new NetPartSelect(sub, off, expr_width());
sel->set_line(*this); sel->set_line(*this);
@ -967,11 +1088,11 @@ NetNet* NetESelect::synthesize(Design *des)
* expressions to the B and A inputs. This way, when the select input * expressions to the B and A inputs. This way, when the select input
* is one, the B input, which is the true expression, is selected. * is one, the B input, which is the true expression, is selected.
*/ */
NetNet* NetETernary::synthesize(Design *des) NetNet* NetETernary::synthesize(Design *des, NetScope*scope)
{ {
NetNet*csig = cond_->synthesize(des), NetNet*csig = cond_->synthesize(des, scope),
*tsig = true_val_->synthesize(des), *tsig = true_val_->synthesize(des, scope),
*fsig = false_val_->synthesize(des); *fsig = false_val_->synthesize(des, scope);
if (csig == 0 || tsig == 0 || fsig == 0) return 0; if (csig == 0 || tsig == 0 || fsig == 0) return 0;
@ -993,7 +1114,7 @@ NetNet* NetETernary::synthesize(Design *des)
perm_string path = csig->scope()->local_symbol(); perm_string path = csig->scope()->local_symbol();
assert(csig->vector_width() == 1); ivl_assert(*this, csig->vector_width() == 1);
unsigned width=expr_width(); unsigned width=expr_width();
NetNet*osig = new NetNet(csig->scope(), path, NetNet::IMPLICIT, width); NetNet*osig = new NetNet(csig->scope(), path, NetNet::IMPLICIT, width);
@ -1025,26 +1146,25 @@ NetNet* NetETernary::synthesize(Design *des)
* a bit more work needs to be done. Return a temporary that represents * a bit more work needs to be done. Return a temporary that represents
* the selected word. * the selected word.
*/ */
NetNet* NetESignal::synthesize(Design*des) NetNet* NetESignal::synthesize(Design*des, NetScope*scope)
{ {
if (word_ == 0) if (word_ == 0)
return net_; return net_;
NetScope*scope = net_->scope();
NetNet*tmp = new NetNet(scope, scope->local_symbol(), NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, net_->vector_width()); NetNet::IMPLICIT, net_->vector_width());
tmp->set_line(*this); tmp->set_line(*this);
tmp->local_flag(true); tmp->local_flag(true);
tmp->data_type(net_->data_type()); tmp->data_type(net_->data_type());
// For NetExpr objects, the word index is already converted to
// a canonical (lsb==0) address. Just use the index directly.
if (NetEConst*index_co = dynamic_cast<NetEConst*> (word_)) { if (NetEConst*index_co = dynamic_cast<NetEConst*> (word_)) {
long index = index_co->value().as_long(); long index = index_co->value().as_long();
assert(net_->array_index_is_valid(index));
index = net_->array_index_to_address(index);
connect(tmp->pin(0), net_->pin(index)); connect(tmp->pin(0), net_->pin(index));
} else { } else {
unsigned selwid = word_->expr_width(); unsigned selwid = word_->expr_width();
@ -1053,7 +1173,7 @@ NetNet* NetESignal::synthesize(Design*des)
mux->set_line(*this); mux->set_line(*this);
des->add_node(mux); des->add_node(mux);
NetNet*index_net = word_->synthesize(des); NetNet*index_net = word_->synthesize(des, scope);
connect(mux->pin_Address(), index_net->pin(0)); connect(mux->pin_Address(), index_net->pin(0));
connect(tmp->pin(0), mux->pin_Result()); connect(tmp->pin(0), mux->pin_Result());
@ -1061,22 +1181,68 @@ NetNet* NetESignal::synthesize(Design*des)
return tmp; return tmp;
} }
NetNet* NetESFunc::synthesize(Design*des) NetNet* NetESFunc::synthesize(Design*des, NetScope*scope)
{ {
cerr << get_fileline() << ": sorry: cannot synthesize system function: "
<< *this << " in this context" << endl; const struct sfunc_return_type*def = lookup_sys_func(name_);
des->errors += 1;
return 0; /* We cannot use the default value for system functions in a
* continuous assignment since the function name is NULL. */
if (def == 0 || def->name == 0) {
cerr << get_fileline() << ": error: System function "
<< name_ << " not defined in system "
"table or SFT file(s)." << endl;
des->errors += 1;
return 0;
}
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Net system function "
<< name_ << " returns " << def->type << endl;
}
NetSysFunc*net = new NetSysFunc(scope, scope->local_symbol(),
def, 1+nparms_);
net->set_line(*this);
des->add_node(net);
NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, def->wid);
osig->local_flag(true);
osig->set_signed(def->type==IVL_VT_REAL? true : false);
osig->data_type(def->type);
osig->set_line(*this);
connect(net->pin(0), osig->pin(0));
unsigned errors = 0;
for (unsigned idx = 0 ; idx < nparms_ ; idx += 1) {
NetNet*tmp = parms_[idx]->synthesize(des, scope);
if (tmp == 0) {
cerr << get_fileline() << ": error: Unable to elaborate "
<< "argument " << idx << " of call to " << name_ <<
"." << endl;
errors += 1;
des->errors += 1;
continue;
}
connect(net->pin(1+idx), tmp->pin(0));
}
if (errors > 0) return 0;
return osig;
} }
NetNet* NetEUFunc::synthesize(Design*des) NetNet* NetEUFunc::synthesize(Design*des, NetScope*scope)
{ {
svector<NetNet*> eparms (parms_.count()); svector<NetNet*> eparms (parms_.count());
/* Synthesize the arguments. */ /* Synthesize the arguments. */
bool errors = false; bool errors = false;
for (unsigned idx = 0; idx < eparms.count(); idx += 1) { for (unsigned idx = 0; idx < eparms.count(); idx += 1) {
NetNet*tmp = parms_[idx]->synthesize(des); NetNet*tmp = parms_[idx]->synthesize(des, scope);
if (tmp == 0) { if (tmp == 0) {
cerr << get_fileline() << ": error: Unable to synthesize " cerr << get_fileline() << ": error: Unable to synthesize "
"port " << idx << " of call to " "port " << idx << " of call to "

View File

@ -302,10 +302,6 @@ ivl_variable_type_t NetEBPow::expr_type() const
return IVL_VT_REAL; return IVL_VT_REAL;
if (left_->expr_type() == IVL_VT_REAL) if (left_->expr_type() == IVL_VT_REAL)
return IVL_VT_REAL; return IVL_VT_REAL;
if (left_->has_sign())
return IVL_VT_REAL;
if (right_->has_sign())
return IVL_VT_REAL;
return IVL_VT_LOGIC; return IVL_VT_LOGIC;
} }

View File

@ -103,6 +103,11 @@ void Link::drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*decay)
nexus_->drivers_delays(rise, fall, decay); nexus_->drivers_delays(rise, fall, decay);
} }
void Link::drivers_drive(strength_t drive0, strength_t drive1)
{
nexus_->drivers_drive(drive0, drive1);
}
void Link::drive0(Link::strength_t str) void Link::drive0(Link::strength_t str)
{ {
drive0_ = str; drive0_ = str;
@ -298,6 +303,17 @@ void Nexus::drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*decay)
} }
} }
void Nexus::drivers_drive(Link::strength_t drive0, Link::strength_t drive1)
{
for (Link*cur = list_ ; cur ; cur = cur->next_) {
if (cur->get_dir() != Link::OUTPUT)
continue;
cur->drive0(drive0);
cur->drive1(drive1);
}
}
void Nexus::unlink(Link*that) void Nexus::unlink(Link*that)
{ {
if (name_) { if (name_) {

View File

@ -627,7 +627,10 @@ void NetNet::data_type(ivl_variable_type_t t)
bool NetNet::get_signed() const bool NetNet::get_signed() const
{ {
return signed_; if (data_type_ == IVL_VT_REAL)
return true;
else
return signed_;
} }
void NetNet::set_signed(bool flag) void NetNet::set_signed(bool flag)
@ -2329,6 +2332,8 @@ const NetExpr* NetETernary::false_expr() const
ivl_variable_type_t NetETernary::expr_type() const ivl_variable_type_t NetETernary::expr_type() const
{ {
ivl_assert(*this, true_val_);
ivl_assert(*this, false_val_);
ivl_variable_type_t tru = true_val_->expr_type(); ivl_variable_type_t tru = true_val_->expr_type();
ivl_variable_type_t fal = false_val_->expr_type(); ivl_variable_type_t fal = false_val_->expr_type();
if (tru == IVL_VT_LOGIC && fal == IVL_VT_BOOL) if (tru == IVL_VT_LOGIC && fal == IVL_VT_BOOL)

View File

@ -210,6 +210,10 @@ class Link {
void drive0(strength_t); void drive0(strength_t);
void drive1(strength_t); void drive1(strength_t);
// This sets the drives for all drivers of this link, and not
// just the current link.
void drivers_drive(strength_t d0, strength_t d1);
strength_t drive0() const; strength_t drive0() const;
strength_t drive1() const; strength_t drive1() const;
@ -312,6 +316,7 @@ class Nexus {
verinum::V get_init() const; verinum::V get_init() const;
void drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*decay); void drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*decay);
void drivers_drive(Link::strength_t d0, Link::strength_t d1);
Link*first_nlink(); Link*first_nlink();
const Link* first_nlink()const; const Link* first_nlink()const;
@ -1576,8 +1581,16 @@ class NetExpr : public LineInfo {
virtual NexusSet* nex_input(bool rem_out = true) =0; virtual NexusSet* nex_input(bool rem_out = true) =0;
// Return a version of myself that is structural. This is used // Return a version of myself that is structural. This is used
// for converting expressions to gates. // for converting expressions to gates. The arguments are:
virtual NetNet*synthesize(Design*); //
// des, scope: The context where this work is done
//
// rise/fall/decay: Attach these delays to the driver for the
// expression output.
//
// drive0/drive1: Attach these strengths tp the driver for
// the expression output.
virtual NetNet*synthesize(Design*des, NetScope*scope);
protected: protected:
@ -1615,7 +1628,7 @@ class NetEConst : public NetExpr {
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
virtual NetEConst* dup_expr() const; virtual NetEConst* dup_expr() const;
virtual NetNet*synthesize(Design*); virtual NetNet*synthesize(Design*, NetScope*scope);
virtual NexusSet* nex_input(bool rem_out = true); virtual NexusSet* nex_input(bool rem_out = true);
private: private:
@ -1668,7 +1681,7 @@ class NetECReal : public NetExpr {
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
virtual NetECReal* dup_expr() const; virtual NetECReal* dup_expr() const;
virtual NetNet*synthesize(Design*); virtual NetNet*synthesize(Design*, NetScope*scope);
virtual NexusSet* nex_input(bool rem_out = true); virtual NexusSet* nex_input(bool rem_out = true);
private: private:
@ -2905,7 +2918,7 @@ class NetEUFunc : public NetExpr {
virtual void expr_scan(struct expr_scan_t*) const; virtual void expr_scan(struct expr_scan_t*) const;
virtual NetEUFunc*dup_expr() const; virtual NetEUFunc*dup_expr() const;
virtual NexusSet* nex_input(bool rem_out = true); virtual NexusSet* nex_input(bool rem_out = true);
virtual NetNet* synthesize(Design*des); virtual NetNet* synthesize(Design*des, NetScope*scope);
private: private:
NetScope*scope_; NetScope*scope_;
@ -3120,7 +3133,7 @@ class NetEBAdd : public NetEBinary {
virtual bool set_width(unsigned w, bool last_chance); virtual bool set_width(unsigned w, bool last_chance);
virtual NetEBAdd* dup_expr() const; virtual NetEBAdd* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*); virtual NetNet* synthesize(Design*, NetScope*scope);
private: private:
NetECReal* eval_tree_real_(); NetECReal* eval_tree_real_();
@ -3142,7 +3155,7 @@ class NetEBDiv : public NetEBinary {
virtual bool set_width(unsigned w, bool last_chance); virtual bool set_width(unsigned w, bool last_chance);
virtual NetEBDiv* dup_expr() const; virtual NetEBDiv* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*); virtual NetNet* synthesize(Design*, NetScope*scope);
}; };
/* /*
@ -3169,7 +3182,7 @@ class NetEBBits : public NetEBinary {
virtual NetEBBits* dup_expr() const; virtual NetEBBits* dup_expr() const;
virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetEConst* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*); virtual NetNet* synthesize(Design*, NetScope*scope);
}; };
/* /*
@ -3200,7 +3213,7 @@ class NetEBComp : public NetEBinary {
virtual NetEBComp* dup_expr() const; virtual NetEBComp* dup_expr() const;
virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetEConst* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*); virtual NetNet* synthesize(Design*, NetScope*scope);
private: private:
NetEConst* must_be_leeq_(NetExpr*le, const verinum&rv, bool eq_flag); NetEConst* must_be_leeq_(NetExpr*le, const verinum&rv, bool eq_flag);
@ -3232,7 +3245,7 @@ class NetEBLogic : public NetEBinary {
virtual bool set_width(unsigned w, bool last_chance); virtual bool set_width(unsigned w, bool last_chance);
virtual NetEBLogic* dup_expr() const; virtual NetEBLogic* dup_expr() const;
virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetEConst* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*); virtual NetNet* synthesize(Design*, NetScope*scope);
private: private:
}; };
@ -3270,7 +3283,7 @@ class NetEBMult : public NetEBinary {
virtual bool set_width(unsigned w, bool last_chance); virtual bool set_width(unsigned w, bool last_chance);
virtual NetEBMult* dup_expr() const; virtual NetEBMult* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*); virtual NetNet* synthesize(Design*, NetScope*scope);
private: private:
@ -3292,7 +3305,7 @@ class NetEBPow : public NetEBinary {
virtual bool set_width(unsigned w, bool last_chance); virtual bool set_width(unsigned w, bool last_chance);
virtual NetEBPow* dup_expr() const; virtual NetEBPow* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*); virtual NetNet* synthesize(Design*, NetScope*scope);
private: private:
@ -3324,7 +3337,7 @@ class NetEBShift : public NetEBinary {
virtual NetEBShift* dup_expr() const; virtual NetEBShift* dup_expr() const;
virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetEConst* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*); virtual NetNet* synthesize(Design*, NetScope*scope);
private: private:
}; };
@ -3358,7 +3371,7 @@ class NetEConcat : public NetExpr {
virtual bool set_width(unsigned w, bool last_chance =false); virtual bool set_width(unsigned w, bool last_chance =false);
virtual NetEConcat* dup_expr() const; virtual NetEConcat* dup_expr() const;
virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetEConst* eval_tree(int prune_to_width = -1);
virtual NetNet*synthesize(Design*); virtual NetNet*synthesize(Design*, NetScope*scope);
virtual void expr_scan(struct expr_scan_t*) const; virtual void expr_scan(struct expr_scan_t*) const;
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
@ -3434,7 +3447,7 @@ class NetESelect : public NetExpr {
virtual void expr_scan(struct expr_scan_t*) const; virtual void expr_scan(struct expr_scan_t*) const;
virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetEConst* eval_tree(int prune_to_width = -1);
virtual NetESelect* dup_expr() const; virtual NetESelect* dup_expr() const;
virtual NetNet*synthesize(Design*des); virtual NetNet*synthesize(Design*des, NetScope*scope);
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
private: private:
@ -3514,7 +3527,7 @@ class NetESFunc : public NetExpr {
virtual void expr_scan(struct expr_scan_t*) const; virtual void expr_scan(struct expr_scan_t*) const;
virtual NetESFunc*dup_expr() const; virtual NetESFunc*dup_expr() const;
virtual NetNet*synthesize(Design*); virtual NetNet*synthesize(Design*, NetScope*scope);
private: private:
const char* name_; const char* name_;
@ -3551,7 +3564,7 @@ class NetETernary : public NetExpr {
virtual NexusSet* nex_input(bool rem_out = true); virtual NexusSet* nex_input(bool rem_out = true);
virtual void expr_scan(struct expr_scan_t*) const; virtual void expr_scan(struct expr_scan_t*) const;
virtual void dump(ostream&) const; virtual void dump(ostream&) const;
virtual NetNet*synthesize(Design*); virtual NetNet*synthesize(Design*, NetScope*scope);
private: private:
NetExpr*cond_; NetExpr*cond_;
@ -3588,6 +3601,7 @@ class NetEUnary : public NetExpr {
virtual NetEUnary* dup_expr() const; virtual NetEUnary* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*, NetScope*scope);
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
virtual NexusSet* nex_input(bool rem_out = true); virtual NexusSet* nex_input(bool rem_out = true);
@ -3608,7 +3622,7 @@ class NetEUBits : public NetEUnary {
NetEUBits(char op, NetExpr*ex); NetEUBits(char op, NetExpr*ex);
~NetEUBits(); ~NetEUBits();
virtual NetNet* synthesize(Design*); virtual NetNet* synthesize(Design*, NetScope*scope);
virtual NetExpr* eval_tree(int prune_to_width = -1); virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
@ -3621,7 +3635,7 @@ class NetEUReduce : public NetEUnary {
~NetEUReduce(); ~NetEUReduce();
virtual bool set_width(unsigned w, bool last_chance); virtual bool set_width(unsigned w, bool last_chance);
virtual NetNet* synthesize(Design*); virtual NetNet* synthesize(Design*, NetScope*scope);
virtual NetEUReduce* dup_expr() const; virtual NetEUReduce* dup_expr() const;
virtual NetEConst* eval_tree(int prune_to_width = -1); virtual NetEConst* eval_tree(int prune_to_width = -1);
virtual ivl_variable_type_t expr_type() const; virtual ivl_variable_type_t expr_type() const;
@ -3648,7 +3662,7 @@ class NetESignal : public NetExpr {
virtual bool set_width(unsigned, bool last_chance); virtual bool set_width(unsigned, bool last_chance);
virtual NetESignal* dup_expr() const; virtual NetESignal* dup_expr() const;
NetNet* synthesize(Design*des); NetNet* synthesize(Design*des, NetScope*scope);
NexusSet* nex_input(bool rem_out = true); NexusSet* nex_input(bool rem_out = true);
// This is the expression for selecting an array word, if this // This is the expression for selecting an array word, if this

View File

@ -76,6 +76,46 @@ NetNet* add_to_net(Design*des, NetNet*sig, long val)
#endif #endif
} }
NetNet* sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig)
{
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);
if (sig->data_type() == IVL_VT_REAL) {
verireal zero (val);
NetLiteral*zero_obj = new NetLiteral(scope, scope->local_symbol(), zero);
des->add_node(zero_obj);
connect(zero_net->pin(0), zero_obj->pin(0));
} else {
verinum zero ((int64_t)val);
zero = pad_to_width(zero, sig->vector_width());
NetConst*zero_obj = new NetConst(scope, scope->local_symbol(), zero);
des->add_node(zero_obj);
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) NetNet* cast_to_int(Design*des, NetScope*scope, NetNet*src, unsigned wid)
{ {
if (src->data_type() != IVL_VT_REAL) if (src->data_type() != IVL_VT_REAL)
@ -170,6 +210,27 @@ NetEConst* make_const_x(unsigned long wid)
return resx; return resx;
} }
NetEConst* make_const_0(unsigned long wid)
{
verinum xxx (verinum::V0, wid);
NetEConst*resx = new NetEConst(xxx);
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) NetExpr* condition_reduce(NetExpr*expr)
{ {
if (expr->expr_width() == 1) 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. * 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*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 * These functions make various sorts of expressions, given operands
@ -113,6 +114,12 @@ extern NetExpr*make_sub_expr(long val, NetExpr*expr);
* Make a NetEConst object that contains only X bits. * Make a NetEConst object that contains only X bits.
*/ */
extern NetEConst*make_const_x(unsigned long wid); extern NetEConst*make_const_x(unsigned long wid);
extern NetEConst*make_const_0(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 * In some cases the lval is accessible as a pointer to the head of
@ -130,9 +137,11 @@ extern unsigned count_lval_width(const class NetAssign_*first);
* The expr_width is the width of the context where the expression is * The expr_width is the width of the context where the expression is
* being elaborated, or -1 if the expression is self-determined width. * being elaborated, or -1 if the expression is self-determined width.
* *
* Also, the prune_width is the maximum width of the result, and it * The prune_width is the maximum width of the result, and is passed
* passed to the eval_tree method of the expression to limit constant * to the eval_tree method of the expression to limit constant
* results if possible. * results. The evaluation will prune any constant result down to the
* prune_width (if >0) so should only be used at the point where it is
* bound to the destination.
*/ */
class PExpr; class PExpr;
extern NetExpr* elab_and_eval(Design*des, NetScope*scope, extern NetExpr* elab_and_eval(Design*des, NetScope*scope,

View File

@ -295,6 +295,9 @@ void PEBinary::dump(ostream&out) const
case 'l': case 'l':
out << "<<"; out << "<<";
break; break;
case 'L':
out << "<=";
break;
case 'n': case 'n':
out << "!="; out << "!=";
break; break;

View File

@ -1,7 +1,7 @@
%{ %{
/* /*
* Copyright (c) 2000-2007 Stephen Williams (steve@icarus.com) * Copyright (c) 2000-2008 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -141,7 +141,7 @@ static void make_DFF_CE(Design*des, NetProcTop*top, NetEvWait*wclk,
NetEvProbe*pclk = eclk->probe(0); NetEvProbe*pclk = eclk->probe(0);
NetESignal*d = dynamic_cast<NetESignal*> (asn->rval()); NetESignal*d = dynamic_cast<NetESignal*> (asn->rval());
NetNet*ce = cexp? cexp->synthesize(des) : 0; NetNet*ce = cexp? cexp->synthesize(des, top->scope()) : 0;
if (d == 0) { if (d == 0) {
cerr << asn->get_fileline() << ": internal error: " cerr << asn->get_fileline() << ": internal error: "

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1999-2000 Stephen Williams (steve@icarus.com) * Copyright (c) 1999-2008 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -16,9 +16,6 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/ */
#ifdef HAVE_CVS_IDENT
#ident "$Id: synth.cc,v 1.14 2002/08/12 01:35:00 steve Exp $"
#endif
# include "config.h" # include "config.h"
@ -36,12 +33,13 @@
class do_expr : public proc_match_t { class do_expr : public proc_match_t {
public: public:
do_expr(Design*d) do_expr(Design*d, NetScope*s)
: des_(d) { } : des_(d), scope_(s) { }
private: private:
Design*des_; Design*des_;
NetScope*scope_;
virtual int assign(NetAssign*); virtual int assign(NetAssign*);
virtual int assign_nb(NetAssignNB*); virtual int assign_nb(NetAssignNB*);
@ -55,7 +53,7 @@ int do_expr::assign(NetAssign*stmt)
if (dynamic_cast<NetESignal*>(stmt->rval())) if (dynamic_cast<NetESignal*>(stmt->rval()))
return 0; return 0;
NetNet*tmp = stmt->rval()->synthesize(des_); NetNet*tmp = stmt->rval()->synthesize(des_, scope_);
if (tmp == 0) if (tmp == 0)
return 0; return 0;
@ -70,7 +68,7 @@ int do_expr::assign_nb(NetAssignNB*stmt)
if (dynamic_cast<NetESignal*>(stmt->rval())) if (dynamic_cast<NetESignal*>(stmt->rval()))
return 0; return 0;
NetNet*tmp = stmt->rval()->synthesize(des_); NetNet*tmp = stmt->rval()->synthesize(des_, scope_);
if (tmp == 0) if (tmp == 0)
return 0; return 0;
@ -84,7 +82,7 @@ int do_expr::condit(NetCondit*stmt)
{ {
/* synthesize the condition expression, if necessary. */ /* synthesize the condition expression, if necessary. */
if (! dynamic_cast<NetESignal*>(stmt->expr())) { if (! dynamic_cast<NetESignal*>(stmt->expr())) {
NetNet*tmp = stmt->expr()->synthesize(des_); NetNet*tmp = stmt->expr()->synthesize(des_, scope_);
if (tmp) { if (tmp) {
NetESignal*tmpe = new NetESignal(tmp); NetESignal*tmpe = new NetESignal(tmp);
@ -144,13 +142,13 @@ void synth_f::process(class Design*des, class NetProcTop*top)
void synth_f::proc_always_(class Design*des) void synth_f::proc_always_(class Design*des)
{ {
do_expr expr_pat(des); do_expr expr_pat(des, top_->scope());
top_->statement()->match_proc(&expr_pat); top_->statement()->match_proc(&expr_pat);
} }
void synth_f::proc_initial_(class Design*des) void synth_f::proc_initial_(class Design*des)
{ {
do_expr expr_pat(des); do_expr expr_pat(des, top_->scope());
top_->statement()->match_proc(&expr_pat); top_->statement()->match_proc(&expr_pat);
} }
@ -159,28 +157,3 @@ void synth(Design*des)
synth_f synth_obj; synth_f synth_obj;
des->functor(&synth_obj); des->functor(&synth_obj);
} }
/*
* $Log: synth.cc,v $
* Revision 1.14 2002/08/12 01:35:00 steve
* conditional ident string using autoconfig.
*
* Revision 1.13 2002/06/05 03:44:25 steve
* Add support for memory words in l-value of
* non-blocking assignments, and remove the special
* NetAssignMem_ and NetAssignMemNB classes.
*
* Revision 1.12 2001/07/25 03:10:49 steve
* Create a config.h.in file to hold all the config
* junk, and support gcc 3.0. (Stephan Boettcher)
*
* Revision 1.11 2000/11/22 21:18:42 steve
* synthesize the rvalue of <= statements.
*
* Revision 1.10 2000/05/13 20:55:47 steve
* Use yacc based synthesizer.
*
* Revision 1.9 2000/04/16 22:57:34 steve
* Catch expressions that are part of conditionals.
*/

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002-2007 Stephen Williams (steve@icarus.com) * Copyright (c) 2002-2008 Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -60,7 +60,7 @@ bool NetProc::synth_sync(Design*des, NetScope*scope, NetFF*ff,
bool NetAssignBase::synth_async(Design*des, NetScope*scope, bool NetAssignBase::synth_async(Design*des, NetScope*scope,
const NetBus&nex_map, NetBus&nex_out) const NetBus&nex_map, NetBus&nex_out)
{ {
NetNet*rsig = rval_->synthesize(des); NetNet*rsig = rval_->synthesize(des, scope);
assert(rsig); assert(rsig);
NetNet*lsig = lval_->sig(); NetNet*lsig = lval_->sig();
@ -155,7 +155,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
const NetBus&nex_map, NetBus&nex_out) const NetBus&nex_map, NetBus&nex_out)
{ {
/* Synthesize the select expression. */ /* Synthesize the select expression. */
NetNet*esig = expr_->synthesize(des); NetNet*esig = expr_->synthesize(des, scope);
unsigned sel_width = esig->vector_width(); unsigned sel_width = esig->vector_width();
assert(sel_width > 0); assert(sel_width > 0);

View File

@ -168,12 +168,23 @@ static int draw_number_real(ivl_expr_t exp)
unsigned long mant = 0, mask = -1UL; unsigned long mant = 0, mask = -1UL;
int vexp = 0x1000; int vexp = 0x1000;
for (idx = 0 ; idx < wid ; idx += 1) { for (idx = 0 ; idx < wid && idx < 8*sizeof(mant) ; idx += 1) {
mask <<= 1; mask <<= 1;
if (bits[idx] == '1') if (bits[idx] == '1')
mant |= 1 << idx; mant |= 1 << idx;
} }
for ( ; idx < wid ; idx += 1) {
if (ivl_expr_signed(exp) && (bits[idx] == bits[8*sizeof(mant)-1]))
continue;
if (bits[idx] == '0')
continue;
fprintf(stderr, "internal error: mantissa doesn't fit!\n");
assert(0);
}
/* If this is actually a negative number, then get the /* If this is actually a negative number, then get the
positive equivalent, and set the sign bit in the exponent positive equivalent, and set the sign bit in the exponent
field. field.
@ -188,8 +199,8 @@ static int draw_number_real(ivl_expr_t exp)
vexp |= 0x4000; vexp |= 0x4000;
} }
fprintf(vvp_out, " %%loadi/wr %d, %lu, %d; load(num)= %c%lu\n", fprintf(vvp_out, " %%loadi/wr %d, %lu, %d; load(num)= %c%lu (wid=%u)\n",
res, mant, vexp, (vexp&0x4000)? '-' : '+', mant); res, mant, vexp, (vexp&0x4000)? '-' : '+', mant, wid);
return res; return res;
} }

View File

@ -1650,15 +1650,19 @@ static void draw_lpm_re(ivl_lpm_t net, const char*type)
static void draw_lpm_repeat(ivl_lpm_t net) static void draw_lpm_repeat(ivl_lpm_t net)
{ {
fprintf(vvp_out, "L_%p .repeat %u, %u, %s;\n", net, const char*dly = draw_lpm_output_delay(net);
fprintf(vvp_out, "L_%p%s .repeat %u, %u, %s;\n", net, dly,
ivl_lpm_width(net), ivl_lpm_size(net), ivl_lpm_width(net), ivl_lpm_size(net),
draw_net_input(ivl_lpm_data(net,0))); draw_net_input(ivl_lpm_data(net,0)));
} }
static void draw_lpm_sign_ext(ivl_lpm_t net) static void draw_lpm_sign_ext(ivl_lpm_t net)
{ {
fprintf(vvp_out, "L_%p .extend/s %u, %s;\n", const char*dly = draw_lpm_output_delay(net);
net, ivl_lpm_width(net),
fprintf(vvp_out, "L_%p%s .extend/s %u, %s;\n",
net, dly, ivl_lpm_width(net),
draw_net_input(ivl_lpm_data(net,0))); draw_net_input(ivl_lpm_data(net,0)));
} }

View File

@ -330,24 +330,24 @@ void vvp_arith_mult::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
{ {
dispatch_operand_(ptr, bit); dispatch_operand_(ptr, bit);
if (wid_ > 8 * sizeof(unsigned long)) { if (wid_ > 8 * sizeof(long)) {
wide_(ptr); wide_(ptr);
return ; return ;
} }
unsigned long a; long a;
if (! vector4_to_value(op_a_, a)) { if (! vector4_to_value(op_a_, a, true, true)) {
vvp_send_vec4(ptr.ptr()->out, x_val_); vvp_send_vec4(ptr.ptr()->out, x_val_);
return; return;
} }
unsigned long b; long b;
if (! vector4_to_value(op_b_, b)) { if (! vector4_to_value(op_b_, b, true, true)) {
vvp_send_vec4(ptr.ptr()->out, x_val_); vvp_send_vec4(ptr.ptr()->out, x_val_);
return; return;
} }
unsigned long val = a * b; long val = a * b;
assert(wid_ <= 8*sizeof(val)); assert(wid_ <= 8*sizeof(val));
vvp_vector4_t vval (wid_); vvp_vector4_t vval (wid_);
@ -364,105 +364,6 @@ void vvp_arith_mult::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
} }
#if 0
void vvp_arith_mult::set(vvp_ipoint_t i, bool push, unsigned val, unsigned)
{
put(i, val);
vvp_ipoint_t base = ipoint_make(i,0);
if(wid_ > 8*sizeof(unsigned long)) {
wide(base, push);
return;
}
unsigned long a = 0, b = 0;
for (unsigned idx = 0 ; idx < wid_ ; idx += 1) {
vvp_ipoint_t ptr = ipoint_index(base,idx);
functor_t obj = functor_index(ptr);
unsigned val = obj->ival;
if (val & 0xaa) {
output_x_(base, push);
return;
}
if (val & 0x01)
a += 1UL << idx;
if (val & 0x04)
b += 1UL << idx;
}
output_val_(base, push, a*b);
}
#endif
#if 0
void vvp_arith_mult::wide(vvp_ipoint_t base, bool push)
{
unsigned char *a, *b, *sum;
a = new unsigned char[wid_];
b = new unsigned char[wid_];
sum = new unsigned char[wid_];
unsigned mxa = 0;
unsigned mxb = 0;
for (unsigned idx = 0 ; idx < wid_ ; idx += 1) {
vvp_ipoint_t ptr = ipoint_index(base, idx);
functor_t obj = functor_index(ptr);
unsigned ival = obj->ival;
if (ival & 0xaa) {
output_x_(base, push);
delete[]sum;
delete[]b;
delete[]a;
return;
}
if((a[idx] = ((ival & 0x01) != 0))) mxa=idx+1;
if((b[idx] = ((ival & 0x04) != 0))) mxb=idx;
sum[idx] = 0;
}
/* do the a*b multiply using the long method we learned in
grade school. We know at this point that there are no X or
Z values in the a or b vectors. */
for(unsigned i=0 ; i<=mxb ; i += 1) {
if(b[i]) {
unsigned char carry=0;
unsigned char temp;
for(unsigned j=0 ; j<=mxa ; j += 1) {
if((i+j) >= wid_)
break;
temp=sum[i+j] + a[j] + carry;
sum[i+j]=(temp&1);
carry=(temp>>1);
}
}
}
for (unsigned idx = 0 ; idx < wid_ ; idx += 1) {
vvp_ipoint_t ptr = ipoint_index(base,idx);
functor_t obj = functor_index(ptr);
unsigned val = sum[idx];
obj->put_oval(val, push);
}
delete[]sum;
delete[]b;
delete[]a;
}
#endif
// Power // Power
vvp_arith_pow::vvp_arith_pow(unsigned wid, bool signed_flag) vvp_arith_pow::vvp_arith_pow(unsigned wid, bool signed_flag)
@ -701,7 +602,11 @@ void vvp_cmp_ne::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit)
{ {
dispatch_operand_(ptr, bit); dispatch_operand_(ptr, bit);
assert(op_a_.size() == op_b_.size()); if (op_a_.size() != op_b_.size()) {
cerr << "internal error: vvp_cmp_ne: op_a_=" << op_a_
<< ", op_b_=" << op_b_ << endl;
assert(op_a_.size() == op_b_.size());
}
vvp_vector4_t res (1); vvp_vector4_t res (1);
res.set_bit(0, BIT4_0); res.set_bit(0, BIT4_0);

View File

@ -1117,13 +1117,7 @@ static bool of_CMPIU_the_hard_way(vthread_t thr, vvp_code_t cp)
thr_check_addr(thr, idx1+wid-1); thr_check_addr(thr, idx1+wid-1);
vvp_bit4_t lv = thr_get_bit(thr, idx1); vvp_bit4_t lv = thr_get_bit(thr, idx1);
if (bit4_is_xz(lv)) { vvp_bit4_t eq = BIT4_1;
thr_put_bit(thr, 4, BIT4_X);
thr_put_bit(thr, 5, BIT4_X);
thr_put_bit(thr, 6, BIT4_0);
}
vvp_bit4_t eq = BIT4_0;
for (unsigned idx = 0 ; idx < wid ; idx += 1) { for (unsigned idx = 0 ; idx < wid ; idx += 1) {
vvp_bit4_t rv = (imm & 1UL)? BIT4_1 : BIT4_0; vvp_bit4_t rv = (imm & 1UL)? BIT4_1 : BIT4_0;
imm >>= 1UL; imm >>= 1UL;
@ -1131,12 +1125,13 @@ static bool of_CMPIU_the_hard_way(vthread_t thr, vvp_code_t cp)
if (bit4_is_xz(lv)) { if (bit4_is_xz(lv)) {
eq = BIT4_X; eq = BIT4_X;
} else if (lv != rv) { } else if (lv != rv) {
eq = BIT4_0;
break; break;
} }
if (idx1 >= 4) { if (idx1 >= 4) {
idx1 += 1; idx1 += 1;
if (idx1 < wid) if ((idx+1) < wid)
lv = thr_get_bit(thr, idx1); lv = thr_get_bit(thr, idx1);
} }
} }

View File

@ -1849,7 +1849,7 @@ static void div_mod (vvp_vector2_t dividend, vvp_vector2_t divisor,
mask >>= 1; mask >>= 1;
} }
remainder = dividend; remainder = vvp_vector2_t(dividend, mask.size());
} }
vvp_vector2_t operator / (const vvp_vector2_t&dividend, vvp_vector2_t operator / (const vvp_vector2_t&dividend,