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;
}
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))
return expr;
@ -109,7 +109,7 @@ static NetExpr* make_delay_nets(Design*des, NetExpr*expr)
if (dynamic_cast<NetEConst*> (expr))
return expr;
NetNet*sig = expr->synthesize(des);
NetNet*sig = expr->synthesize(des, scope);
if (sig == 0) {
cerr << expr->get_fileline() << ": error: Expression " << *expr
<< " is not suitable for delay expression." << endl;
@ -132,17 +132,17 @@ void PDelays::eval_delays(Design*des, NetScope*scope,
if (delay_[0]) {
rise_time = calculate_val(des, scope, delay_[0]);
if (as_nets_flag)
rise_time = make_delay_nets(des, rise_time);
rise_time = make_delay_nets(des, scope, rise_time);
if (delay_[1]) {
fall_time = calculate_val(des, scope, delay_[1]);
if (as_nets_flag)
fall_time = make_delay_nets(des, fall_time);
fall_time = make_delay_nets(des, scope, fall_time);
if (delay_[2]) {
decay_time = calculate_val(des, scope, delay_[2]);
if (as_nets_flag)
decay_time = make_delay_nets(des, decay_time);
decay_time = make_delay_nets(des, scope, decay_time);
} else {
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
// 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
// this is the same as the lval width.
//
@ -492,6 +492,10 @@ class PEUnary : public PExpr {
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 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_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);
private:
@ -679,7 +687,7 @@ class PETernary : public PExpr {
const NetExpr* decay,
Link::strength_t drive0,
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;
virtual NetETernary*elaborate_pexpr(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:
NetAssign_* elaborate_lval(Design*, NetScope*scope) const;
NetExpr* elaborate_rval_(Design*, NetScope*, unsigned lv_width) const;
PExpr* delay_;
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
{
o << setw(ind) << "" << "NetSignExtend: "
<< name() << " output width=" << width_ << endl;
o << setw(ind) << "" << "NetSignExtend: " << name();
if (rise_time())
o << " #(" << *rise_time()
<< "," << *fall_time()
<< "," << *decay_time() << ")";
else
o << " #(.,.,.)";
o << " output width=" << width_ << endl;
dump_node_pins(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.
*/
NetExpr* PEBinary::elaborate_expr_base_(Design*des,
NetExpr*lp, NetExpr*rp,
int expr_wid) const
NetExpr*lp, NetExpr*rp,
int expr_wid) const
{
bool flag;
@ -180,6 +180,13 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des,
break;
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->set_line(*this);
break;
@ -203,60 +210,12 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des,
break;
case 'l': // <<
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 < 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);
tmp = elaborate_expr_base_lshift_(des, lp, rp, expr_wid);
break;
case 'r': // >>
case 'R': // >>>
tmp = new NetEBShift(op_, lp, rp);
tmp->set_line(*this);
tmp = elaborate_expr_base_rshift_(des, lp, rp, expr_wid);
break;
case '^':
@ -271,11 +230,7 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des,
case '+':
case '-':
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);
tmp = elaborate_expr_base_add_(des, lp, rp, expr_wid);
break;
case 'E': /* === */
@ -323,6 +278,224 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des,
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
{
return 1;
@ -376,6 +549,11 @@ unsigned PEBShift::test_width(Design*des, NetScope*scope,
// The right expression is self-determined and has no impact
// on the expression size that is generated.
if (wid_left < min)
wid_left = min;
if (wid_left < lval)
wid_left = lval;
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);
if (net != 0) {
const name_component_t&name_tail = path_.back();
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
if (!name_tail.index.empty())
use_sel = name_tail.index.back().sel;
// If there is a part/bit select expression, then process it
// here. This constrains the results no matter what kind the
// name is.
unsigned use_width = net->vector_width();
switch (use_sel) {
case index_component_t::SEL_NONE:
break;
case index_component_t::SEL_PART:
{ long msb, lsb;
calculate_parts_(des, scope, msb, lsb);
use_width = 1 + ((msb>lsb)? (msb-lsb) : (lsb-msb));
break;
}
case index_component_t::SEL_IDX_UP:
case index_component_t::SEL_IDX_DO:
{ unsigned long tmp = 0;
calculate_up_do_width_(des, scope, tmp);
use_width = tmp;
break;
}
case index_component_t::SEL_BIT:
use_width = 1;
break;
default:
ivl_assert(*this, 0);
}
const name_component_t&name_tail = path_.back();
index_component_t::ctype_t use_sel = index_component_t::SEL_NONE;
if (!name_tail.index.empty())
use_sel = name_tail.index.back().sel;
unsigned use_width = UINT_MAX;
switch (use_sel) {
case index_component_t::SEL_NONE:
break;
case index_component_t::SEL_PART:
{ long msb, lsb;
calculate_parts_(des, scope, msb, lsb);
use_width = 1 + ((msb>lsb)? (msb-lsb) : (lsb-msb));
break;
}
case index_component_t::SEL_IDX_UP:
case index_component_t::SEL_IDX_DO:
{ unsigned long tmp = 0;
calculate_up_do_width_(des, scope, tmp);
use_width = tmp;
break;
}
case index_component_t::SEL_BIT:
use_width = 1;
break;
default:
ivl_assert(*this, 0);
}
if (use_width != UINT_MAX)
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;
@ -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
// are not scopes. If this is not a system task argument, then
// 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
* 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
{
assert(expr_);
@ -1962,17 +2190,54 @@ NetETernary*PETernary::elaborate_expr(Design*des, NetScope*scope,
<< " 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)
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) {
delete con;
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) {
delete con;
delete tru;
@ -1998,6 +2263,38 @@ NetETernary*PETernary::elaborate_expr(Design*des, NetScope*scope,
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,
int expr_wid, bool) const
{
@ -2055,6 +2352,8 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope,
delete ip;
} else {
if (expr_wid > 0)
ip = pad_to_width(ip, expr_wid);
tmp = new NetEUnary(op_, ip);
tmp->set_line(*this);
}

View File

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

View File

@ -91,7 +91,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const
return;
}
assert(lval->pin_count() == 1);
ivl_assert(*this, lval->pin_count() == 1);
if (debug_elaborate) {
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;
}
/* Handle the special case that the rval is simply an
identifier. Get the rval as a NetNet, then use NetBUFZ
objects to connect it to the l-value. This is necessary to
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;
}
bool unsized_flag = false;
unsigned use_width = pin(1)->test_width(des, scope, lval->vector_width(),
lval->vector_width(), unsized_flag);
/* Cast the right side when needed. */
if ((lval->data_type() == IVL_VT_REAL &&
rid->data_type() != IVL_VT_REAL)) {
rid = cast_to_real(des, scope, rid);
} else if ((lval->data_type() != IVL_VT_REAL &&
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;
if (debug_elaborate) {
cerr << get_fileline() << ": debug: PGAssign: r-value tested "
<< "width is " << use_width
<< ", min=" << lval->vector_width()
<< ", unsized_flag=" << (unsized_flag?"true":"false") << endl;
}
/* Elaborate the r-value. Account for the initial decays,
which are going to be attached to the last gate before the
generated NetNet. */
NetNet*rval = pin(1)->elaborate_net(des, scope,
lval->vector_width(),
0, 0, 0,
drive0, drive1);
if (rval == 0) {
int expr_wid = unsized_flag? -1 : use_width;
NetExpr*rval_expr = elab_and_eval(des, scope, pin(1),
expr_wid, lval->vector_width());
if (rval_expr == 0) {
cerr << get_fileline() << ": error: Unable to elaborate r-value: "
<< *pin(1) << endl;
des->errors += 1;
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) {
cerr << get_fileline() << ": debug: PGAssign: elaborated r-value"
<< " width="<<rval->vector_width()
<< ", type="<< rval->data_type() << endl;
<< " width="<< rval->vector_width()
<< ", type="<< rval->data_type()
<< ", expr=" << *rval_expr << endl;
}
assert(lval && rval);
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. */
if ((lval->data_type() == IVL_VT_REAL &&
rval->data_type() != IVL_VT_REAL)) {
rval = cast_to_real(des, scope, rval);
need_driver_flag = false;
} else if ((lval->data_type() != IVL_VT_REAL &&
rval->data_type() == IVL_VT_REAL)) {
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
(perhaps it is explicitly sized) the pad it out to be the
right width so that something is connected to all the bits
of the l-value. */
if (lval->vector_width() > rval->vector_width())
rval = pad_to_width(des, rval, lval->vector_width());
if (lval->vector_width() > rval->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
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::TRI, lval->vector_width());
osig->set_line(*this);
osig->local_flag(true);
osig->data_type(rval->data_type());
connect(osig->pin(0), tmp->pin(0));
rval = osig;
need_driver_flag = false;
}
/* If there is a rise/fall/decay time, then attach that delay
to the drivers for this net. */
if (rise_time || fall_time || decay_time) {
rval->pin(0).drivers_delays(rise_time, fall_time, decay_time);
if (need_driver_flag) {
NetBUFZ*driver = new NetBUFZ(scope, scope->local_symbol(),
rval->vector_width());
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));
if (lval->local_flag())
@ -1705,6 +1595,29 @@ NetAssign_* PAssign_::elaborate_lval(Design*des, NetScope*scope) const
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
* 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);
assert(rval());
/* Elaborate the r-value expression, then try to evaluate it. */
/* 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());
NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv));
if (rv == 0) return 0;
assert(rv);
@ -1964,12 +1865,7 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const
NetAssign_*lv = elaborate_lval(des, scope);
if (lv == 0) return 0;
assert(rval());
/* Elaborate and precalculate the r-value. */
NetExpr*rv = elab_and_eval(des, scope, rval(), count_lval_width(lv));
if (rv == 0)
return 0;
NetExpr*rv = elaborate_rval_(des, scope, count_lval_width(lv));
/* Handle the (common) case that the r-value is a vector. This
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?
// Get a net form.
condit_sig = tmp->synthesize(des);
condit_sig = tmp->synthesize(des, scope);
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 result_flag = true;
error_implicit = true;
if (gn_specify_blocks_flag) {
// Elaborate specparams
@ -3722,6 +3619,7 @@ bool Module::elaborate(Design*des, NetScope*scope) const
// complex.
const list<PGate*>&gl = get_gates();
error_implicit = false;
for (list<PGate*>::const_iterator gt = gl.begin()
; gt != gl.end()
; gt ++ ) {
@ -3729,6 +3627,8 @@ bool Module::elaborate(Design*des, NetScope*scope) const
(*gt)->elaborate(des, scope);
}
error_implicit = true;
// Elaborate the behaviors, making processes out of them. This
// involves scanning the PProcess* list, creating a NetProcTop
// 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*vtmp;
@ -606,11 +613,14 @@ NetEConst* NetEBComp::eval_eqeq_(bool ne_flag)
for (unsigned idx = 0 ; idx < top ; idx += 1) {
bool x_bit_present = false;
switch (lv.get(idx)) {
case verinum::Vx:
case verinum::Vz:
res = verinum::Vx;
x_bit_present = true;
break;
default:
@ -622,17 +632,20 @@ NetEConst* NetEBComp::eval_eqeq_(bool ne_flag)
case verinum::Vx:
case verinum::Vz:
res = verinum::Vx;
x_bit_present = true;
break;
default:
break;
}
if (res == verinum::Vx)
break;
if (x_bit_present)
continue;
if (rv.get(idx) != lv.get(idx))
if (rv.get(idx) != lv.get(idx)) {
res = ne_res;
break;
}
}
if (res != verinum::Vx) {

View File

@ -26,14 +26,14 @@
# include "netmisc.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;
if (NetEConst*tmp = dynamic_cast<NetEConst*>(expr)) {
verireal vrl(tmp->value().as_double());
NetECReal rlval(vrl);
sig = rlval.synthesize(des);
sig = rlval.synthesize(des, scope);
} else {
cerr << obj->get_fileline() << ": sorry: Cannot convert "
"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. */
bool process_binary_args(Design*des, NetExpr*left, NetExpr*right,
NetNet*&lsig, NetNet*&rsig, bool&real_args,
NetExpr*obj)
static bool process_binary_args(Design*des, NetScope*scope,
NetExpr*left, NetExpr*right,
NetNet*&lsig, NetNet*&rsig, bool&real_args,
NetExpr*obj)
{
if (left->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
are not real, though we can convert constants. */
if (left->expr_type() == IVL_VT_REAL) {
lsig = left->synthesize(des);
lsig = left->synthesize(des, scope);
} 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) {
rsig = right->synthesize(des);
rsig = right->synthesize(des, scope);
} else {
rsig = convert_to_real_const(des, right, obj);
rsig = convert_to_real_const(des, scope, right, obj);
}
} else {
real_args = false;
lsig = left->synthesize(des);
rsig = right->synthesize(des);
lsig = left->synthesize(des, scope);
rsig = right->synthesize(des, scope);
}
@ -77,7 +78,7 @@ bool process_binary_args(Design*des, NetExpr*left, NetExpr*right,
else return false;
}
NetNet* NetExpr::synthesize(Design*des)
NetNet* NetExpr::synthesize(Design*des, NetScope*scope)
{
cerr << get_fileline() << ": internal error: cannot synthesize expression: "
<< *this << endl;
@ -88,13 +89,13 @@ NetNet* NetExpr::synthesize(Design*des)
/*
* 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;
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)) {
return 0;
}
@ -138,10 +139,10 @@ NetNet* NetEBAdd::synthesize(Design*des)
* signals, then just connect a single gate to each bit of the vector
* of the expression.
*/
NetNet* NetEBBits::synthesize(Design*des)
NetNet* NetEBBits::synthesize(Design*des, NetScope*scope)
{
NetNet*lsig = left_->synthesize(des);
NetNet*rsig = right_->synthesize(des);
NetNet*lsig = left_->synthesize(des, scope);
NetNet*rsig = right_->synthesize(des, scope);
if (lsig == 0 || rsig == 0) return 0;
@ -154,9 +155,6 @@ NetNet* NetEBBits::synthesize(Design*des)
return 0;
}
NetScope*scope = lsig->scope();
assert(scope);
unsigned width = lsig->vector_width();
if (rsig->vector_width() > width) width = rsig->vector_width();
@ -205,13 +203,13 @@ NetNet* NetEBBits::synthesize(Design*des)
return osig;
}
NetNet* NetEBComp::synthesize(Design*des)
NetNet* NetEBComp::synthesize(Design*des, NetScope*scope)
{
NetNet *lsig=0, *rsig=0;
unsigned width;
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)) {
return 0;
}
@ -222,13 +220,16 @@ NetNet* NetEBComp::synthesize(Design*des)
width = lsig->vector_width();
if (rsig->vector_width() > width) width = rsig->vector_width();
lsig = pad_to_width(des, lsig, width);
rsig = pad_to_width(des, rsig, width);
if (lsig->get_signed())
lsig = pad_to_width_signed(des, lsig, width);
else
lsig = pad_to_width(des, lsig, width);
if (rsig->get_signed())
rsig = pad_to_width_signed(des, rsig, width);
else
rsig = pad_to_width(des, rsig, width);
}
NetScope*scope = lsig->scope();
assert(scope);
NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, 1);
osig->set_line(*this);
@ -236,10 +237,30 @@ NetNet* NetEBComp::synthesize(Design*des)
osig->data_type(IVL_VT_LOGIC);
bool signed_compare = lsig->get_signed() && rsig->get_signed();
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Comparison (" << op_ << ")"
<< " is " << (signed_compare? "signed" : "unsigned")
<< endl;
cerr << get_fileline() << ": : lsig is "
<< (lsig->get_signed()? "signed" : "unsigned")
<< " rsig is " << (rsig->get_signed()? "signed" : "unsigned")
<< endl;
}
if (op_ == 'E' || op_ == 'N') {
NetCaseCmp*gate = new NetCaseCmp(scope, scope->local_symbol(),
width, op_=='E'?true:false);
gate->set_line(*this);
connect(gate->pin(0), osig->pin(0));
connect(gate->pin(1), lsig->pin(0));
connect(gate->pin(2), rsig->pin(0));
des->add_node(gate);
return osig;
}
/* Handle the special case of a single bit equality
operation. Make an XNOR gate instead of a comparator. */
if ((width == 1) && ((op_ == 'e') || (op_ == 'E')) && !real_args) {
if ((width == 1) && (op_ == 'e') && !real_args) {
NetLogic*gate = new NetLogic(scope, scope->local_symbol(),
3, NetLogic::XNOR, 1);
gate->set_line(*this);
@ -253,7 +274,7 @@ NetNet* NetEBComp::synthesize(Design*des)
/* Handle the special case of a single bit inequality
operation. This is similar to single bit equality, but uses
an XOR instead of an XNOR gate. */
if ((width == 1) && ((op_ == 'n') || (op_ == 'N')) && !real_args) {
if ((width == 1) && (op_ == 'n') && !real_args) {
NetLogic*gate = new NetLogic(scope, scope->local_symbol(),
3, NetLogic::XOR, 1);
gate->set_line(*this);
@ -321,12 +342,12 @@ NetNet* NetEBComp::synthesize(Design*des)
return osig;
}
NetNet* NetEBPow::synthesize(Design*des)
NetNet* NetEBPow::synthesize(Design*des, NetScope*scope)
{
NetNet *lsig=0, *rsig=0;
unsigned width;
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)) {
return 0;
}
@ -334,9 +355,6 @@ NetNet* NetEBPow::synthesize(Design*des)
if (real_args) width = 1;
else width = expr_width();
NetScope*scope = lsig->scope();
assert(scope);
NetPow*powr = new NetPow(scope, scope->local_symbol(), width,
lsig->vector_width(),
rsig->vector_width());
@ -359,12 +377,12 @@ NetNet* NetEBPow::synthesize(Design*des)
return osig;
}
NetNet* NetEBMult::synthesize(Design*des)
NetNet* NetEBMult::synthesize(Design*des, NetScope*scope)
{
NetNet *lsig=0, *rsig=0;
unsigned width;
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)) {
return 0;
}
@ -372,9 +390,6 @@ NetNet* NetEBMult::synthesize(Design*des)
if (real_args) width = 1;
else width = expr_width();
NetScope*scope = lsig->scope();
assert(scope);
NetMult*mult = new NetMult(scope, scope->local_symbol(),
width,
lsig->vector_width(),
@ -398,12 +413,12 @@ NetNet* NetEBMult::synthesize(Design*des)
return osig;
}
NetNet* NetEBDiv::synthesize(Design*des)
NetNet* NetEBDiv::synthesize(Design*des, NetScope*scope)
{
NetNet *lsig=0, *rsig=0;
unsigned width;
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)) {
return 0;
}
@ -411,12 +426,11 @@ NetNet* NetEBDiv::synthesize(Design*des)
if (real_args) width = 1;
else width = expr_width();
NetScope*scope = lsig->scope();
NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, width);
osig->set_line(*this);
osig->data_type(lsig->data_type());
osig->set_signed(has_sign());
osig->local_flag(true);
switch (op()) {
@ -427,6 +441,7 @@ NetNet* NetEBDiv::synthesize(Design*des)
lsig->vector_width(),
rsig->vector_width());
div->set_line(*this);
div->set_signed(has_sign());
des->add_node(div);
connect(div->pin_DataA(), lsig->pin(0));
@ -471,10 +486,10 @@ NetNet* NetEBDiv::synthesize(Design*des)
return osig;
}
NetNet* NetEBLogic::synthesize(Design*des)
NetNet* NetEBLogic::synthesize(Design*des, NetScope*scope)
{
NetNet*lsig = left_->synthesize(des);
NetNet*rsig = right_->synthesize(des);
NetNet*lsig = left_->synthesize(des, scope);
NetNet*rsig = right_->synthesize(des, scope);
if (lsig == 0 || rsig == 0) return 0;
@ -487,9 +502,6 @@ NetNet* NetEBLogic::synthesize(Design*des)
return 0;
}
NetScope*scope = lsig->scope();
assert(scope);
NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, 1);
osig->data_type(expr_type());
@ -551,11 +563,11 @@ NetNet* NetEBLogic::synthesize(Design*des)
return osig;
}
NetNet* NetEBShift::synthesize(Design*des)
NetNet* NetEBShift::synthesize(Design*des, NetScope*scope)
{
eval_expr(right_);
NetNet*lsig = left_->synthesize(des);
NetNet*lsig = left_->synthesize(des, scope);
if (lsig == 0) return 0;
@ -568,10 +580,8 @@ NetNet* NetEBShift::synthesize(Design*des)
return 0;
}
bool right_flag = op_ == 'r' || op_ == 'R';
bool signed_flag = op_ == 'R';
NetScope*scope = lsig->scope();
const bool right_flag = op_ == 'r' || op_ == 'R';
const bool signed_flag = op_ == 'R';
/* Detect the special case where the shift amount is
constant. Evaluate the shift amount, and simply reconnect
@ -580,7 +590,7 @@ NetNet* NetEBShift::synthesize(Design*des)
verinum shift_v = rcon->value();
long shift = shift_v.as_long();
if (op() == 'r')
if (right_flag)
shift = 0-shift;
if (shift == 0)
@ -593,34 +603,13 @@ NetNet* NetEBShift::synthesize(Design*des)
// ushift is the amount of pad created by the shift.
unsigned long ushift = shift>=0? shift : -shift;
if (ushift > osig->vector_width())
ushift = osig->vector_width();
ivl_assert(*this, ushift < osig->vector_width());
// part_width is the bits of the vector that survive the shift.
unsigned long part_width = osig->vector_width() - ushift;
verinum znum (verinum::V0, ushift, true);
NetConst*zcon = new NetConst(scope, scope->local_symbol(),
znum);
des->add_node(zcon);
/* Detect the special case that the shift is the size of
the whole expression. Simply connect the pad to the
osig and escape. */
if (ushift >= osig->vector_width()) {
connect(zcon->pin(0), osig->pin(0));
return osig;
}
NetNet*zsig = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, znum.len());
zsig->data_type(osig->data_type());
zsig->local_flag(true);
zsig->set_line(*this);
connect(zcon->pin(0), zsig->pin(0));
/* Create a part select to reduce the width of the lsig
to the amount left by the shift. */
// Create a part select to reduce the width of the lsig
// to the amount left by the shift.
NetPartSelect*psel = new NetPartSelect(lsig, shift<0? ushift : 0,
part_width,
NetPartSelect::VP);
@ -633,6 +622,34 @@ NetNet* NetEBShift::synthesize(Design*des)
psig->set_line(*this);
connect(psig->pin(0), psel->pin(0));
// Handle the special case of a signed right shift. In
// this case, use the NetSignExtend device to pad the
// result to the desired width.
if (signed_flag && right_flag) {
NetSignExtend*pad = new NetSignExtend(scope, scope->local_symbol(),
osig->vector_width());
des->add_node(pad);
pad->set_line(*this);
connect(pad->pin(1), psig->pin(0));
connect(pad->pin(0), osig->pin(0));
return osig;
}
// Other cases are handled by zero-extending on the
// proper end.
verinum znum (verinum::V0, ushift, true);
NetConst*zcon = new NetConst(scope, scope->local_symbol(),
znum);
des->add_node(zcon);
NetNet*zsig = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, znum.len());
zsig->data_type(osig->data_type());
zsig->local_flag(true);
zsig->set_line(*this);
connect(zcon->pin(0), zsig->pin(0));
NetConcat*ccat = new NetConcat(scope, scope->local_symbol(),
osig->vector_width(), 2);
ccat->set_line(*this);
@ -652,7 +669,7 @@ NetNet* NetEBShift::synthesize(Design*des)
return osig;
}
NetNet*rsig = right_->synthesize(des);
NetNet*rsig = right_->synthesize(des, scope);
if (rsig == 0) return 0;
@ -678,13 +695,13 @@ NetNet* NetEBShift::synthesize(Design*des)
return osig;
}
NetNet* NetEConcat::synthesize(Design*des)
NetNet* NetEConcat::synthesize(Design*des, NetScope*scope)
{
/* First, synthesize the operands. */
NetNet**tmp = new NetNet*[parms_.count()];
bool flag = true;
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)
flag = false;
}
@ -692,9 +709,7 @@ NetNet* NetEConcat::synthesize(Design*des)
if (flag == false)
return 0;
assert(tmp[0]);
NetScope*scope = tmp[0]->scope();
assert(scope);
ivl_assert(*this, tmp[0]);
/* Make a NetNet object to carry the output vector. */
perm_string path = scope->local_symbol();
@ -712,7 +727,9 @@ NetNet* NetEConcat::synthesize(Design*des)
unsigned cur_pin = 1;
for (unsigned rpt = 0; rpt < repeat(); rpt += 1) {
for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) {
connect(concat->pin(cur_pin), tmp[parms_.count()-idx-1]->pin(0));
unsigned concat_item = parms_.count()-idx-1;
ivl_assert(*this, tmp[concat_item]);
connect(concat->pin(cur_pin), tmp[concat_item]->pin(0));
cur_pin += 1;
}
}
@ -721,11 +738,8 @@ NetNet* NetEConcat::synthesize(Design*des)
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();
unsigned width=expr_width();
@ -743,11 +757,8 @@ NetNet* NetEConst::synthesize(Design*des)
/*
* 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();
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
* 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;
@ -782,9 +793,6 @@ NetNet* NetEUBits::synthesize(Design*des)
return 0;
}
NetScope*scope = isig->scope();
assert(scope);
unsigned width = isig->vector_width();
NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, width);
@ -810,9 +818,46 @@ NetNet* NetEUBits::synthesize(Design*des)
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;
@ -824,9 +869,6 @@ NetNet* NetEUReduce::synthesize(Design*des)
return 0;
}
NetScope*scope = isig->scope();
assert(scope);
NetNet*osig = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, 1);
osig->data_type(expr_type());
@ -849,7 +891,7 @@ NetNet* NetEUReduce::synthesize(Design*des)
rtype = NetUReduce::XOR;
break;
case 'A':
rtype = NetUReduce::XNOR;
rtype = NetUReduce::NAND;
break;
case 'X':
rtype = NetUReduce::XNOR;
@ -871,22 +913,101 @@ NetNet* NetEUReduce::synthesize(Design*des)
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;
NetScope*scope = sub->scope();
NetNet*off = 0;
// Detect the special case that there is a base expression and
// it is constant. In this case we can generate fixed part selects.
if (NetEConst*base_const = dynamic_cast<NetEConst*>(base_)) {
verinum base_tmp = base_const->value();
ivl_assert(*this, base_tmp.is_defined());
long base_val = base_tmp.as_long();
unsigned select_width = expr_width();
// Any below X bits?
NetNet*below = 0;
if (base_val < 0) {
unsigned below_width = abs(base_val);
base_val = 0;
ivl_assert(*this, below_width < select_width);
select_width -= below_width;
below = make_const_x(des, scope, below_width);
below->set_line(*this);
}
// Any above bits?.
NetNet*above = 0;
if (base_val+select_width > sub->vector_width()) {
select_width = sub->vector_width() - base_val;
unsigned above_width = expr_width() - select_width;
above = make_const_x(des, scope, above_width);
above->set_line(*this);
}
// Make the make part select.
NetPartSelect*sel = new NetPartSelect(sub, base_val, select_width,
NetPartSelect::VP);
des->add_node(sel);
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, select_width);
tmp->data_type(sub->data_type());
tmp->local_flag(true);
tmp->set_line(*this);
connect(sel->pin(0), tmp->pin(0));
unsigned concat_count = 1;
if (above)
concat_count += 1;
if (below)
concat_count += 1;
if (concat_count > 1) {
NetConcat*cat = new NetConcat(scope, scope->local_symbol(),
expr_width(), concat_count);
cat->set_line(*this);
des->add_node(cat);
if (below) {
connect(cat->pin(1), below->pin(0));
connect(cat->pin(2), tmp->pin(0));
} else {
connect(cat->pin(1), tmp->pin(0));
}
if (above) {
connect(cat->pin(concat_count), above->pin(0));
}
tmp = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, expr_width());
tmp->data_type(sub->data_type());
tmp->local_flag(true);
tmp->set_line(*this);
connect(cat->pin(0), tmp->pin(0));
}
return tmp;
}
// This handles the case that the NetESelect exists to do an
// actual part/bit select. Generate a NetPartSelect object to
// do the work, and replace "sub" with the selected output.
if (base_ != 0) {
off = base_->synthesize(des);
off = base_->synthesize(des, scope);
NetPartSelect*sel = new NetPartSelect(sub, off, expr_width());
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
* 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),
*tsig = true_val_->synthesize(des),
*fsig = false_val_->synthesize(des);
NetNet*csig = cond_->synthesize(des, scope),
*tsig = true_val_->synthesize(des, scope),
*fsig = false_val_->synthesize(des, scope);
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();
assert(csig->vector_width() == 1);
ivl_assert(*this, csig->vector_width() == 1);
unsigned width=expr_width();
NetNet*osig = new NetNet(csig->scope(), path, NetNet::IMPLICIT, width);
@ -1025,26 +1146,25 @@ NetNet* NetETernary::synthesize(Design *des)
* a bit more work needs to be done. Return a temporary that represents
* the selected word.
*/
NetNet* NetESignal::synthesize(Design*des)
NetNet* NetESignal::synthesize(Design*des, NetScope*scope)
{
if (word_ == 0)
return net_;
NetScope*scope = net_->scope();
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::IMPLICIT, net_->vector_width());
tmp->set_line(*this);
tmp->local_flag(true);
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_)) {
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));
} else {
unsigned selwid = word_->expr_width();
@ -1053,7 +1173,7 @@ NetNet* NetESignal::synthesize(Design*des)
mux->set_line(*this);
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(tmp->pin(0), mux->pin_Result());
@ -1061,22 +1181,68 @@ NetNet* NetESignal::synthesize(Design*des)
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;
des->errors += 1;
return 0;
const struct sfunc_return_type*def = lookup_sys_func(name_);
/* 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());
/* Synthesize the arguments. */
bool errors = false;
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) {
cerr << get_fileline() << ": error: Unable to synthesize "
"port " << idx << " of call to "

View File

@ -302,10 +302,6 @@ ivl_variable_type_t NetEBPow::expr_type() const
return IVL_VT_REAL;
if (left_->expr_type() == 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;
}

View File

@ -103,6 +103,11 @@ void Link::drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*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)
{
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)
{
if (name_) {

View File

@ -627,7 +627,10 @@ void NetNet::data_type(ivl_variable_type_t t)
bool NetNet::get_signed() const
{
return signed_;
if (data_type_ == IVL_VT_REAL)
return true;
else
return signed_;
}
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_assert(*this, true_val_);
ivl_assert(*this, false_val_);
ivl_variable_type_t tru = true_val_->expr_type();
ivl_variable_type_t fal = false_val_->expr_type();
if (tru == IVL_VT_LOGIC && fal == IVL_VT_BOOL)

View File

@ -210,6 +210,10 @@ class Link {
void drive0(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 drive1() const;
@ -312,6 +316,7 @@ class Nexus {
verinum::V get_init() const;
void drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*decay);
void drivers_drive(Link::strength_t d0, Link::strength_t d1);
Link*first_nlink();
const Link* first_nlink()const;
@ -1576,8 +1581,16 @@ class NetExpr : public LineInfo {
virtual NexusSet* nex_input(bool rem_out = true) =0;
// Return a version of myself that is structural. This is used
// for converting expressions to gates.
virtual NetNet*synthesize(Design*);
// for converting expressions to gates. The arguments are:
//
// 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:
@ -1615,7 +1628,7 @@ class NetEConst : public NetExpr {
virtual void dump(ostream&) const;
virtual NetEConst* dup_expr() const;
virtual NetNet*synthesize(Design*);
virtual NetNet*synthesize(Design*, NetScope*scope);
virtual NexusSet* nex_input(bool rem_out = true);
private:
@ -1668,7 +1681,7 @@ class NetECReal : public NetExpr {
virtual void dump(ostream&) const;
virtual NetECReal* dup_expr() const;
virtual NetNet*synthesize(Design*);
virtual NetNet*synthesize(Design*, NetScope*scope);
virtual NexusSet* nex_input(bool rem_out = true);
private:
@ -2905,7 +2918,7 @@ class NetEUFunc : public NetExpr {
virtual void expr_scan(struct expr_scan_t*) const;
virtual NetEUFunc*dup_expr() const;
virtual NexusSet* nex_input(bool rem_out = true);
virtual NetNet* synthesize(Design*des);
virtual NetNet* synthesize(Design*des, NetScope*scope);
private:
NetScope*scope_;
@ -3120,7 +3133,7 @@ class NetEBAdd : public NetEBinary {
virtual bool set_width(unsigned w, bool last_chance);
virtual NetEBAdd* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*);
virtual NetNet* synthesize(Design*, NetScope*scope);
private:
NetECReal* eval_tree_real_();
@ -3142,7 +3155,7 @@ class NetEBDiv : public NetEBinary {
virtual bool set_width(unsigned w, bool last_chance);
virtual NetEBDiv* dup_expr() const;
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 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 NetEConst* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*);
virtual NetNet* synthesize(Design*, NetScope*scope);
private:
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 NetEBLogic* dup_expr() const;
virtual NetEConst* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*);
virtual NetNet* synthesize(Design*, NetScope*scope);
private:
};
@ -3270,7 +3283,7 @@ class NetEBMult : public NetEBinary {
virtual bool set_width(unsigned w, bool last_chance);
virtual NetEBMult* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*);
virtual NetNet* synthesize(Design*, NetScope*scope);
private:
@ -3292,7 +3305,7 @@ class NetEBPow : public NetEBinary {
virtual bool set_width(unsigned w, bool last_chance);
virtual NetEBPow* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*);
virtual NetNet* synthesize(Design*, NetScope*scope);
private:
@ -3324,7 +3337,7 @@ class NetEBShift : public NetEBinary {
virtual NetEBShift* dup_expr() const;
virtual NetEConst* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*);
virtual NetNet* synthesize(Design*, NetScope*scope);
private:
};
@ -3358,7 +3371,7 @@ class NetEConcat : public NetExpr {
virtual bool set_width(unsigned w, bool last_chance =false);
virtual NetEConcat* dup_expr() const;
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 dump(ostream&) const;
@ -3434,7 +3447,7 @@ class NetESelect : public NetExpr {
virtual void expr_scan(struct expr_scan_t*) const;
virtual NetEConst* eval_tree(int prune_to_width = -1);
virtual NetESelect* dup_expr() const;
virtual NetNet*synthesize(Design*des);
virtual NetNet*synthesize(Design*des, NetScope*scope);
virtual void dump(ostream&) const;
private:
@ -3514,7 +3527,7 @@ class NetESFunc : public NetExpr {
virtual void expr_scan(struct expr_scan_t*) const;
virtual NetESFunc*dup_expr() const;
virtual NetNet*synthesize(Design*);
virtual NetNet*synthesize(Design*, NetScope*scope);
private:
const char* name_;
@ -3551,7 +3564,7 @@ class NetETernary : public NetExpr {
virtual NexusSet* nex_input(bool rem_out = true);
virtual void expr_scan(struct expr_scan_t*) const;
virtual void dump(ostream&) const;
virtual NetNet*synthesize(Design*);
virtual NetNet*synthesize(Design*, NetScope*scope);
private:
NetExpr*cond_;
@ -3588,6 +3601,7 @@ class NetEUnary : public NetExpr {
virtual NetEUnary* dup_expr() const;
virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual NetNet* synthesize(Design*, NetScope*scope);
virtual ivl_variable_type_t expr_type() const;
virtual NexusSet* nex_input(bool rem_out = true);
@ -3608,7 +3622,7 @@ class NetEUBits : public NetEUnary {
NetEUBits(char op, NetExpr*ex);
~NetEUBits();
virtual NetNet* synthesize(Design*);
virtual NetNet* synthesize(Design*, NetScope*scope);
virtual NetExpr* eval_tree(int prune_to_width = -1);
virtual ivl_variable_type_t expr_type() const;
@ -3621,7 +3635,7 @@ class NetEUReduce : public NetEUnary {
~NetEUReduce();
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 NetEConst* eval_tree(int prune_to_width = -1);
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 NetESignal* dup_expr() const;
NetNet* synthesize(Design*des);
NetNet* synthesize(Design*des, NetScope*scope);
NexusSet* nex_input(bool rem_out = true);
// 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
}
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)
{
if (src->data_type() != IVL_VT_REAL)
@ -170,6 +210,27 @@ NetEConst* make_const_x(unsigned long wid)
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)
{
if (expr->expr_width() == 1)

View File

@ -91,6 +91,7 @@ extern NetNet*crop_to_width(Design*des, NetNet*n, unsigned w);
* return a new NetNet value that is the output of an addition.
*/
extern NetNet*add_to_net(Design*des, NetNet*sig, long val);
extern NetNet*sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig);
/*
* These functions make various sorts of expressions, given operands
@ -113,6 +114,12 @@ extern NetExpr*make_sub_expr(long val, NetExpr*expr);
* Make a NetEConst object that contains only X bits.
*/
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
@ -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
* being elaborated, or -1 if the expression is self-determined width.
*
* Also, the prune_width is the maximum width of the result, and it
* passed to the eval_tree method of the expression to limit constant
* results if possible.
* The prune_width is the maximum width of the result, and is passed
* to the eval_tree method of the expression to limit constant
* 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;
extern NetExpr* elab_and_eval(Design*des, NetScope*scope,

View File

@ -295,6 +295,9 @@ void PEBinary::dump(ostream&out) const
case 'l':
out << "<<";
break;
case 'L':
out << "<=";
break;
case 'n':
out << "!=";
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
* 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);
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) {
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
* 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
* 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"
@ -36,12 +33,13 @@
class do_expr : public proc_match_t {
public:
do_expr(Design*d)
: des_(d) { }
do_expr(Design*d, NetScope*s)
: des_(d), scope_(s) { }
private:
Design*des_;
NetScope*scope_;
virtual int assign(NetAssign*);
virtual int assign_nb(NetAssignNB*);
@ -55,7 +53,7 @@ int do_expr::assign(NetAssign*stmt)
if (dynamic_cast<NetESignal*>(stmt->rval()))
return 0;
NetNet*tmp = stmt->rval()->synthesize(des_);
NetNet*tmp = stmt->rval()->synthesize(des_, scope_);
if (tmp == 0)
return 0;
@ -70,7 +68,7 @@ int do_expr::assign_nb(NetAssignNB*stmt)
if (dynamic_cast<NetESignal*>(stmt->rval()))
return 0;
NetNet*tmp = stmt->rval()->synthesize(des_);
NetNet*tmp = stmt->rval()->synthesize(des_, scope_);
if (tmp == 0)
return 0;
@ -84,7 +82,7 @@ int do_expr::condit(NetCondit*stmt)
{
/* synthesize the condition expression, if necessary. */
if (! dynamic_cast<NetESignal*>(stmt->expr())) {
NetNet*tmp = stmt->expr()->synthesize(des_);
NetNet*tmp = stmt->expr()->synthesize(des_, scope_);
if (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)
{
do_expr expr_pat(des);
do_expr expr_pat(des, top_->scope());
top_->statement()->match_proc(&expr_pat);
}
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);
}
@ -159,28 +157,3 @@ void synth(Design*des)
synth_f 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
* 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,
const NetBus&nex_map, NetBus&nex_out)
{
NetNet*rsig = rval_->synthesize(des);
NetNet*rsig = rval_->synthesize(des, scope);
assert(rsig);
NetNet*lsig = lval_->sig();
@ -155,7 +155,7 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
const NetBus&nex_map, NetBus&nex_out)
{
/* Synthesize the select expression. */
NetNet*esig = expr_->synthesize(des);
NetNet*esig = expr_->synthesize(des, scope);
unsigned sel_width = esig->vector_width();
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;
int vexp = 0x1000;
for (idx = 0 ; idx < wid ; idx += 1) {
for (idx = 0 ; idx < wid && idx < 8*sizeof(mant) ; idx += 1) {
mask <<= 1;
if (bits[idx] == '1')
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
positive equivalent, and set the sign bit in the exponent
field.
@ -188,8 +199,8 @@ static int draw_number_real(ivl_expr_t exp)
vexp |= 0x4000;
}
fprintf(vvp_out, " %%loadi/wr %d, %lu, %d; load(num)= %c%lu\n",
res, mant, vexp, (vexp&0x4000)? '-' : '+', mant);
fprintf(vvp_out, " %%loadi/wr %d, %lu, %d; load(num)= %c%lu (wid=%u)\n",
res, mant, vexp, (vexp&0x4000)? '-' : '+', mant, wid);
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)
{
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),
draw_net_input(ivl_lpm_data(net,0)));
}
static void draw_lpm_sign_ext(ivl_lpm_t net)
{
fprintf(vvp_out, "L_%p .extend/s %u, %s;\n",
net, ivl_lpm_width(net),
const char*dly = draw_lpm_output_delay(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)));
}

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);
if (wid_ > 8 * sizeof(unsigned long)) {
if (wid_ > 8 * sizeof(long)) {
wide_(ptr);
return ;
}
unsigned long a;
if (! vector4_to_value(op_a_, a)) {
long a;
if (! vector4_to_value(op_a_, a, true, true)) {
vvp_send_vec4(ptr.ptr()->out, x_val_);
return;
}
unsigned long b;
if (! vector4_to_value(op_b_, b)) {
long b;
if (! vector4_to_value(op_b_, b, true, true)) {
vvp_send_vec4(ptr.ptr()->out, x_val_);
return;
}
unsigned long val = a * b;
long val = a * b;
assert(wid_ <= 8*sizeof(val));
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
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);
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);
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);
vvp_bit4_t lv = thr_get_bit(thr, idx1);
if (bit4_is_xz(lv)) {
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;
vvp_bit4_t eq = BIT4_1;
for (unsigned idx = 0 ; idx < wid ; idx += 1) {
vvp_bit4_t rv = (imm & 1UL)? BIT4_1 : BIT4_0;
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)) {
eq = BIT4_X;
} else if (lv != rv) {
eq = BIT4_0;
break;
}
if (idx1 >= 4) {
idx1 += 1;
if (idx1 < wid)
if ((idx+1) < wid)
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;
}
remainder = dividend;
remainder = vvp_vector2_t(dividend, mask.size());
}
vvp_vector2_t operator / (const vvp_vector2_t&dividend,