Merge branch 'elaborate-net-rework'
This commit is contained in:
commit
90f55a1d00
10
PDelays.cc
10
PDelays.cc
|
|
@ -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
12
PExpr.h
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
477
elab_expr.cc
477
elab_expr.cc
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
28
elab_net.cc
28
elab_net.cc
|
|
@ -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;
|
||||
|
|
|
|||
296
elaborate.cc
296
elaborate.cc
|
|
@ -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.
|
||||
|
|
|
|||
19
eval_tree.cc
19
eval_tree.cc
|
|
@ -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) {
|
||||
|
|
|
|||
430
expr_synth.cc
430
expr_synth.cc
|
|
@ -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 "
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
16
net_link.cc
16
net_link.cc
|
|
@ -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_) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
54
netlist.h
54
netlist.h
|
|
@ -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
|
||||
|
|
|
|||
61
netmisc.cc
61
netmisc.cc
|
|
@ -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)
|
||||
|
|
|
|||
15
netmisc.h
15
netmisc.h
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -295,6 +295,9 @@ void PEBinary::dump(ostream&out) const
|
|||
case 'l':
|
||||
out << "<<";
|
||||
break;
|
||||
case 'L':
|
||||
out << "<=";
|
||||
break;
|
||||
case 'n':
|
||||
out << "!=";
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -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: "
|
||||
|
|
|
|||
45
synth.cc
45
synth.cc
|
|
@ -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.
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
}
|
||||
|
||||
|
|
|
|||
117
vvp/arith.cc
117
vvp/arith.cc
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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÷nd,
|
||||
|
|
|
|||
Loading…
Reference in New Issue