From 1d884cb0e9348e3fcdc65df0f60dee00c8debbc8 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 10 Aug 2008 18:22:34 -0700 Subject: [PATCH 01/27] Shuffle the argument list for the synthesize method. In preparation for using the synthesize method to replace the elaborate_net method of PExpr, rework the interface to the synthesize() method. This changes no fnctionality, but does set up the infrastructure for the next step. --- PDelays.cc | 10 +-- elab_net.cc | 28 +++--- elaborate.cc | 2 +- expr_synth.cc | 235 +++++++++++++++++++++++++++++++------------------- netlist.h | 143 +++++++++++++++++++++++++----- syn-rules.y | 4 +- synth.cc | 45 ++-------- synth2.cc | 6 +- 8 files changed, 304 insertions(+), 169 deletions(-) diff --git a/PDelays.cc b/PDelays.cc index c547a2c08..e39a57122 100644 --- a/PDelays.cc +++ b/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 (expr)) return expr; @@ -109,7 +109,7 @@ static NetExpr* make_delay_nets(Design*des, NetExpr*expr) if (dynamic_cast (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) diff --git a/elab_net.cc b/elab_net.cc index 6cd63c12d..deffb5404 100644 --- a/elab_net.cc +++ b/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(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(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 << "."<synthesize(des); + NetNet* sub_sig = expr->synthesize(des, scope); if (sub_sig == 0) return 0; delete expr; diff --git a/elaborate.cc b/elaborate.cc index ad7c273ab..fae8b52e0 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3472,7 +3472,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); } diff --git a/expr_synth.cc b/expr_synth.cc index df291f6d1..d4b390437 100644 --- a/expr_synth.cc +++ b/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(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,12 @@ 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, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { cerr << get_fileline() << ": internal error: cannot synthesize expression: " << *this << endl; @@ -88,13 +94,18 @@ 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, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { assert((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 +149,15 @@ 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, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { - 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 +170,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 +218,18 @@ NetNet* NetEBBits::synthesize(Design*des) return osig; } -NetNet* NetEBComp::synthesize(Design*des) +NetNet* NetEBComp::synthesize(Design*des, NetScope*scope, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { 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; } @@ -226,9 +244,6 @@ NetNet* NetEBComp::synthesize(Design*des) 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); @@ -321,12 +336,17 @@ NetNet* NetEBComp::synthesize(Design*des) return osig; } -NetNet* NetEBPow::synthesize(Design*des) +NetNet* NetEBPow::synthesize(Design*des, NetScope*scope, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { 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 +354,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 +376,17 @@ NetNet* NetEBPow::synthesize(Design*des) return osig; } -NetNet* NetEBMult::synthesize(Design*des) +NetNet* NetEBMult::synthesize(Design*des, NetScope*scope, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { 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 +394,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 +417,17 @@ NetNet* NetEBMult::synthesize(Design*des) return osig; } -NetNet* NetEBDiv::synthesize(Design*des) +NetNet* NetEBDiv::synthesize(Design*des, NetScope*scope, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { 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,8 +435,6 @@ 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); @@ -471,10 +493,15 @@ NetNet* NetEBDiv::synthesize(Design*des) return osig; } -NetNet* NetEBLogic::synthesize(Design*des) +NetNet* NetEBLogic::synthesize(Design*des, NetScope*scope, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { - 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 +514,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 +575,16 @@ NetNet* NetEBLogic::synthesize(Design*des) return osig; } -NetNet* NetEBShift::synthesize(Design*des) +NetNet* NetEBShift::synthesize(Design*des, NetScope*scope, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { eval_expr(right_); - NetNet*lsig = left_->synthesize(des); + NetNet*lsig = left_->synthesize(des, scope); if (lsig == 0) return 0; @@ -571,8 +600,6 @@ NetNet* NetEBShift::synthesize(Design*des) bool right_flag = op_ == 'r' || op_ == 'R'; bool signed_flag = op_ == 'R'; - NetScope*scope = lsig->scope(); - /* Detect the special case where the shift amount is constant. Evaluate the shift amount, and simply reconnect the left operand to the output, but shifted. */ @@ -652,7 +679,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 +705,18 @@ NetNet* NetEBShift::synthesize(Design*des) return osig; } -NetNet* NetEConcat::synthesize(Design*des) +NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { /* 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; } @@ -693,8 +725,6 @@ NetNet* NetEConcat::synthesize(Design*des) return 0; assert(tmp[0]); - NetScope*scope = tmp[0]->scope(); - assert(scope); /* Make a NetNet object to carry the output vector. */ perm_string path = scope->local_symbol(); @@ -721,11 +751,13 @@ NetNet* NetEConcat::synthesize(Design*des) return osig; } -NetNet* NetEConst::synthesize(Design*des) +NetNet* NetEConst::synthesize(Design*des, NetScope*scope, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { - NetScope*scope = des->find_root_scope(); - assert(scope); - perm_string path = scope->local_symbol(); unsigned width=expr_width(); @@ -743,11 +775,13 @@ 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, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { - 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 +802,14 @@ 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, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { - NetNet*isig = expr_->synthesize(des); + NetNet*isig = expr_->synthesize(des, scope); if (isig == 0) return 0; @@ -782,9 +821,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 +846,14 @@ NetNet* NetEUBits::synthesize(Design*des) return osig; } -NetNet* NetEUReduce::synthesize(Design*des) +NetNet* NetEUReduce::synthesize(Design*des, NetScope*scope, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { - NetNet*isig = expr_->synthesize(des); + NetNet*isig = expr_->synthesize(des, scope); if (isig == 0) return 0; @@ -824,9 +865,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()); @@ -871,22 +909,25 @@ NetNet* NetEUReduce::synthesize(Design*des) return osig; } -NetNet* NetESelect::synthesize(Design *des) +NetNet* NetESelect::synthesize(Design *des, NetScope*scope, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { - NetNet*sub = expr_->synthesize(des); + NetNet*sub = expr_->synthesize(des, scope); if (sub == 0) return 0; - NetScope*scope = sub->scope(); - NetNet*off = 0; // 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 +1008,16 @@ 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, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { - 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; @@ -1025,13 +1071,16 @@ 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, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { 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); @@ -1053,7 +1102,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,7 +1110,12 @@ NetNet* NetESignal::synthesize(Design*des) return tmp; } -NetNet* NetESFunc::synthesize(Design*des) +NetNet* NetESFunc::synthesize(Design*des, NetScope*scope, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { cerr << get_fileline() << ": sorry: cannot synthesize system function: " << *this << " in this context" << endl; @@ -1069,14 +1123,19 @@ NetNet* NetESFunc::synthesize(Design*des) return 0; } -NetNet* NetEUFunc::synthesize(Design*des) +NetNet* NetEUFunc::synthesize(Design*des, NetScope*scope, + const NetExpr* rise, + const NetExpr* fall, + const NetExpr* decay, + Link::strength_t drive0, + Link::strength_t drive1) { svector 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 " diff --git a/netlist.h b/netlist.h index 7818938e8..e2f34b2d1 100644 --- a/netlist.h +++ b/netlist.h @@ -1535,8 +1535,21 @@ 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, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); protected: @@ -1574,7 +1587,12 @@ class NetEConst : public NetExpr { virtual void dump(ostream&) const; virtual NetEConst* dup_expr() const; - virtual NetNet*synthesize(Design*); + virtual NetNet*synthesize(Design*, NetScope*scope, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); virtual NexusSet* nex_input(bool rem_out = true); private: @@ -1627,7 +1645,12 @@ class NetECReal : public NetExpr { virtual void dump(ostream&) const; virtual NetECReal* dup_expr() const; - virtual NetNet*synthesize(Design*); + virtual NetNet*synthesize(Design*, NetScope*scope, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); virtual NexusSet* nex_input(bool rem_out = true); private: @@ -2864,7 +2887,12 @@ 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, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); private: NetScope*scope_; @@ -3058,7 +3086,12 @@ 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, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); private: NetECReal* eval_tree_real_(); @@ -3080,7 +3113,12 @@ 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, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); }; /* @@ -3107,7 +3145,12 @@ 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, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); }; /* @@ -3138,7 +3181,12 @@ 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, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); private: NetEConst* must_be_leeq_(NetExpr*le, const verinum&rv, bool eq_flag); @@ -3169,7 +3217,12 @@ 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, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); private: }; @@ -3207,7 +3260,12 @@ 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, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); private: @@ -3229,7 +3287,12 @@ 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, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); private: @@ -3261,7 +3324,12 @@ 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, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); private: }; @@ -3295,7 +3363,12 @@ 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, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; @@ -3371,7 +3444,12 @@ 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, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); virtual void dump(ostream&) const; private: @@ -3449,7 +3527,12 @@ 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, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); private: const char* name_; @@ -3486,7 +3569,12 @@ 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, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); private: NetExpr*cond_; @@ -3543,7 +3631,12 @@ class NetEUBits : public NetEUnary { NetEUBits(char op, NetExpr*ex); ~NetEUBits(); - virtual NetNet* synthesize(Design*); + virtual NetNet* synthesize(Design*, NetScope*scope, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); virtual NetExpr* eval_tree(int prune_to_width = -1); virtual ivl_variable_type_t expr_type() const; @@ -3556,7 +3649,12 @@ class NetEUReduce : public NetEUnary { ~NetEUReduce(); virtual bool set_width(unsigned w, bool last_chance); - virtual NetNet* synthesize(Design*); + virtual NetNet* synthesize(Design*, NetScope*scope, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); virtual NetEUReduce* dup_expr() const; virtual NetEConst* eval_tree(int prune_to_width = -1); virtual ivl_variable_type_t expr_type() const; @@ -3583,7 +3681,12 @@ 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, + const NetExpr* rise =0, + const NetExpr* fall =0, + const NetExpr* decay =0, + Link::strength_t drive0 =Link::STRONG, + Link::strength_t drive1 =Link::STRONG); NexusSet* nex_input(bool rem_out = true); // This is the expression for selecting an array word, if this diff --git a/syn-rules.y b/syn-rules.y index 49ea2586b..78c4b4588 100644 --- a/syn-rules.y +++ b/syn-rules.y @@ -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 (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: " diff --git a/synth.cc b/synth.cc index e92276d3a..ac2aaeb87 100644 --- a/synth.cc +++ b/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(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(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(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. - */ - diff --git a/synth2.cc b/synth2.cc index 812dceb03..dbd843759 100644 --- a/synth2.cc +++ b/synth2.cc @@ -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); From 6051150c14514d890fa3fb0f1fef4c8ba917a2cd Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 11 Aug 2008 21:21:33 -0700 Subject: [PATCH 02/27] Continuous assign no longer uses elaborate_net. convert the continuous assign elaboration to use elaborate_expr and synthesize methods instead of the elaborate_net methods of PExpr. This exposes problems with the synthesize methods, but it is a better way to do it. --- elaborate.cc | 196 +++++---------------------------------------- expr_synth.cc | 214 ++++++++++++++++++++++---------------------------- net_link.cc | 16 ++++ netlist.h | 139 ++++++-------------------------- 4 files changed, 153 insertions(+), 412 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index fae8b52e0..39cbfc25e 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -99,187 +99,29 @@ 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(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; - } + NetExpr*rval_expr = elab_and_eval(des, scope, pin(1), + lval->vector_width(), + lval->vector_width()); - /* 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 << ":"; - if (fall_time) - cerr << *fall_time << ":"; - else - cerr << ":"; - if (decay_time) - cerr << *decay_time; - else - cerr << ""; - cerr << ")" << endl; - } - - NetBUFZ*dev = new NetBUFZ(scope, scope->local_symbol(), - rid->vector_width()); - connect(lval->pin(0), dev->pin(0)); - connect(rid->pin(0), dev->pin(1)); - dev->rise_time(rise_time); - dev->fall_time(fall_time); - dev->decay_time(decay_time); - dev->pin(0).drive0(drive0); - dev->pin(0).drive1(drive1); - des->add_node(dev); - - } - - return; - } - - /* Elaborate the r-value. Account for the initial decays, - 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) { + 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="<vector_width() + << " width="<< rval->vector_width() << ", type="<< rval->data_type() << endl; } @@ -318,11 +160,13 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const rval = osig; } - /* 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) { + /* 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)); diff --git a/expr_synth.cc b/expr_synth.cc index d4b390437..e9c5d3085 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -78,12 +78,7 @@ static bool process_binary_args(Design*des, NetScope*scope, else return false; } -NetNet* NetExpr::synthesize(Design*des, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +NetNet* NetExpr::synthesize(Design*des, NetScope*scope) { cerr << get_fileline() << ": internal error: cannot synthesize expression: " << *this << endl; @@ -94,12 +89,7 @@ NetNet* NetExpr::synthesize(Design*des, NetScope*scope, /* * Make an LPM_ADD_SUB device from addition operators. */ -NetNet* NetEBAdd::synthesize(Design*des, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +NetNet* NetEBAdd::synthesize(Design*des, NetScope*scope) { assert((op()=='+') || (op()=='-')); @@ -149,12 +139,7 @@ NetNet* NetEBAdd::synthesize(Design*des, NetScope*scope, * signals, then just connect a single gate to each bit of the vector * of the expression. */ -NetNet* NetEBBits::synthesize(Design*des, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +NetNet* NetEBBits::synthesize(Design*des, NetScope*scope) { NetNet*lsig = left_->synthesize(des, scope); NetNet*rsig = right_->synthesize(des, scope); @@ -218,12 +203,7 @@ NetNet* NetEBBits::synthesize(Design*des, NetScope*scope, return osig; } -NetNet* NetEBComp::synthesize(Design*des, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +NetNet* NetEBComp::synthesize(Design*des, NetScope*scope) { NetNet *lsig=0, *rsig=0; @@ -336,12 +316,7 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope, return osig; } -NetNet* NetEBPow::synthesize(Design*des, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +NetNet* NetEBPow::synthesize(Design*des, NetScope*scope) { NetNet *lsig=0, *rsig=0; unsigned width; @@ -376,12 +351,7 @@ NetNet* NetEBPow::synthesize(Design*des, NetScope*scope, return osig; } -NetNet* NetEBMult::synthesize(Design*des, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +NetNet* NetEBMult::synthesize(Design*des, NetScope*scope) { NetNet *lsig=0, *rsig=0; unsigned width; @@ -417,12 +387,7 @@ NetNet* NetEBMult::synthesize(Design*des, NetScope*scope, return osig; } -NetNet* NetEBDiv::synthesize(Design*des, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +NetNet* NetEBDiv::synthesize(Design*des, NetScope*scope) { NetNet *lsig=0, *rsig=0; unsigned width; @@ -493,12 +458,7 @@ NetNet* NetEBDiv::synthesize(Design*des, NetScope*scope, return osig; } -NetNet* NetEBLogic::synthesize(Design*des, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +NetNet* NetEBLogic::synthesize(Design*des, NetScope*scope) { NetNet*lsig = left_->synthesize(des, scope); NetNet*rsig = right_->synthesize(des, scope); @@ -575,12 +535,7 @@ NetNet* NetEBLogic::synthesize(Design*des, NetScope*scope, return osig; } -NetNet* NetEBShift::synthesize(Design*des, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +NetNet* NetEBShift::synthesize(Design*des, NetScope*scope) { eval_expr(right_); @@ -705,12 +660,7 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope, return osig; } -NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +NetNet* NetEConcat::synthesize(Design*des, NetScope*scope) { /* First, synthesize the operands. */ NetNet**tmp = new NetNet*[parms_.count()]; @@ -751,12 +701,7 @@ NetNet* NetEConcat::synthesize(Design*des, NetScope*scope, return osig; } -NetNet* NetEConst::synthesize(Design*des, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +NetNet* NetEConst::synthesize(Design*des, NetScope*scope) { perm_string path = scope->local_symbol(); unsigned width=expr_width(); @@ -775,12 +720,7 @@ NetNet* NetEConst::synthesize(Design*des, NetScope*scope, /* * Create a NetLiteral object to represent real valued constants. */ -NetNet* NetECReal::synthesize(Design*des, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +NetNet* NetECReal::synthesize(Design*des, NetScope*scope) { perm_string path = scope->local_symbol(); @@ -802,12 +742,7 @@ NetNet* NetECReal::synthesize(Design*des, NetScope*scope, * 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, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +NetNet* NetEUBits::synthesize(Design*des, NetScope*scope) { NetNet*isig = expr_->synthesize(des, scope); @@ -846,12 +781,25 @@ NetNet* NetEUBits::synthesize(Design*des, NetScope*scope, return osig; } -NetNet* NetEUReduce::synthesize(Design*des, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +NetNet* NetEUnary::synthesize(Design*des, NetScope*scope) +{ + if (op_ == '+') + return expr_->synthesize(des, scope); + + if (op_ == '-') { + NetExpr*tmp = make_sub_expr(0, expr_); + NetNet*sig = tmp->synthesize(des, scope); + delete tmp; + 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); @@ -909,12 +857,7 @@ NetNet* NetEUReduce::synthesize(Design*des, NetScope*scope, return osig; } -NetNet* NetESelect::synthesize(Design *des, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +NetNet* NetESelect::synthesize(Design *des, NetScope*scope) { NetNet*sub = expr_->synthesize(des, scope); @@ -1008,12 +951,7 @@ NetNet* NetESelect::synthesize(Design *des, NetScope*scope, * 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, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +NetNet* NetETernary::synthesize(Design *des, NetScope*scope) { NetNet*csig = cond_->synthesize(des, scope), *tsig = true_val_->synthesize(des, scope), @@ -1071,12 +1009,7 @@ NetNet* NetETernary::synthesize(Design *des, NetScope*scope, * a bit more work needs to be done. Return a temporary that represents * the selected word. */ -NetNet* NetESignal::synthesize(Design*des, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +NetNet* NetESignal::synthesize(Design*des, NetScope*scope) { if (word_ == 0) return net_; @@ -1087,13 +1020,14 @@ NetNet* NetESignal::synthesize(Design*des, NetScope*scope, 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 (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(); @@ -1110,25 +1044,61 @@ NetNet* NetESignal::synthesize(Design*des, NetScope*scope, return tmp; } -NetNet* NetESFunc::synthesize(Design*des, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +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, NetScope*scope, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) +NetNet* NetEUFunc::synthesize(Design*des, NetScope*scope) { svector eparms (parms_.count()); diff --git a/net_link.cc b/net_link.cc index 5b2621b90..f9ee2c19c 100644 --- a/net_link.cc +++ b/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; @@ -295,6 +300,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_) { diff --git a/netlist.h b/netlist.h index e2f34b2d1..aaef219d2 100644 --- a/netlist.h +++ b/netlist.h @@ -178,6 +178,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; @@ -280,6 +284,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; @@ -1544,12 +1549,7 @@ class NetExpr : public LineInfo { // // drive0/drive1: Attach these strengths tp the driver for // the expression output. - virtual NetNet*synthesize(Design*des, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + virtual NetNet*synthesize(Design*des, NetScope*scope); protected: @@ -1587,12 +1587,7 @@ class NetEConst : public NetExpr { virtual void dump(ostream&) const; virtual NetEConst* dup_expr() const; - virtual NetNet*synthesize(Design*, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + virtual NetNet*synthesize(Design*, NetScope*scope); virtual NexusSet* nex_input(bool rem_out = true); private: @@ -1645,12 +1640,7 @@ class NetECReal : public NetExpr { virtual void dump(ostream&) const; virtual NetECReal* dup_expr() const; - virtual NetNet*synthesize(Design*, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + virtual NetNet*synthesize(Design*, NetScope*scope); virtual NexusSet* nex_input(bool rem_out = true); private: @@ -2887,12 +2877,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, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + virtual NetNet* synthesize(Design*des, NetScope*scope); private: NetScope*scope_; @@ -3086,12 +3071,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*, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + virtual NetNet* synthesize(Design*, NetScope*scope); private: NetECReal* eval_tree_real_(); @@ -3113,12 +3093,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*, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + virtual NetNet* synthesize(Design*, NetScope*scope); }; /* @@ -3145,12 +3120,7 @@ class NetEBBits : public NetEBinary { virtual NetEBBits* dup_expr() const; virtual NetEConst* eval_tree(int prune_to_width = -1); - virtual NetNet* synthesize(Design*, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + virtual NetNet* synthesize(Design*, NetScope*scope); }; /* @@ -3181,12 +3151,7 @@ class NetEBComp : public NetEBinary { virtual NetEBComp* dup_expr() const; virtual NetEConst* eval_tree(int prune_to_width = -1); - virtual NetNet* synthesize(Design*, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + virtual NetNet* synthesize(Design*, NetScope*scope); private: NetEConst* must_be_leeq_(NetExpr*le, const verinum&rv, bool eq_flag); @@ -3217,12 +3182,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*, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + virtual NetNet* synthesize(Design*, NetScope*scope); private: }; @@ -3260,12 +3220,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*, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + virtual NetNet* synthesize(Design*, NetScope*scope); private: @@ -3287,12 +3242,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*, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + virtual NetNet* synthesize(Design*, NetScope*scope); private: @@ -3324,12 +3274,7 @@ class NetEBShift : public NetEBinary { virtual NetEBShift* dup_expr() const; virtual NetEConst* eval_tree(int prune_to_width = -1); - virtual NetNet* synthesize(Design*, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + virtual NetNet* synthesize(Design*, NetScope*scope); private: }; @@ -3363,12 +3308,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*, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + virtual NetNet*synthesize(Design*, NetScope*scope); virtual void expr_scan(struct expr_scan_t*) const; virtual void dump(ostream&) const; @@ -3444,12 +3384,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, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + virtual NetNet*synthesize(Design*des, NetScope*scope); virtual void dump(ostream&) const; private: @@ -3527,12 +3462,7 @@ class NetESFunc : public NetExpr { virtual void expr_scan(struct expr_scan_t*) const; virtual NetESFunc*dup_expr() const; - virtual NetNet*synthesize(Design*, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + virtual NetNet*synthesize(Design*, NetScope*scope); private: const char* name_; @@ -3569,12 +3499,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*, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + virtual NetNet*synthesize(Design*, NetScope*scope); private: NetExpr*cond_; @@ -3611,6 +3536,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); @@ -3631,12 +3557,7 @@ class NetEUBits : public NetEUnary { NetEUBits(char op, NetExpr*ex); ~NetEUBits(); - virtual NetNet* synthesize(Design*, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + virtual NetNet* synthesize(Design*, NetScope*scope); virtual NetExpr* eval_tree(int prune_to_width = -1); virtual ivl_variable_type_t expr_type() const; @@ -3649,12 +3570,7 @@ class NetEUReduce : public NetEUnary { ~NetEUReduce(); virtual bool set_width(unsigned w, bool last_chance); - virtual NetNet* synthesize(Design*, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + 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; @@ -3681,12 +3597,7 @@ class NetESignal : public NetExpr { virtual bool set_width(unsigned, bool last_chance); virtual NetESignal* dup_expr() const; - NetNet* synthesize(Design*des, NetScope*scope, - const NetExpr* rise =0, - const NetExpr* fall =0, - const NetExpr* decay =0, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG); + NetNet* synthesize(Design*des, NetScope*scope); NexusSet* nex_input(bool rem_out = true); // This is the expression for selecting an array word, if this From 3d1f363be8247ffa4db80c835ceed636ac580de3 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 12 Aug 2008 21:03:38 -0700 Subject: [PATCH 03/27] Handle special case of net assigned to net. When nets are assigned directly to a net, we need to create a driver to carry the strength. Normally, the implied drive of a continuous assignment is carried by whatever gate the r-value expression ends with, but with simble net-to-net assignment, there is no net so we need to install a BUFZ to carry the assignment. --- elaborate.cc | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/elaborate.cc b/elaborate.cc index 39cbfc25e..fab58d9e9 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -128,13 +128,22 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const 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(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 @@ -158,6 +167,26 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const osig->data_type(rval->data_type()); connect(osig->pin(0), tmp->pin(0)); rval = osig; + need_driver_flag = false; + } + + 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. */ From dc6d3f4afbfef52cdf4a7c2190cfa7fe69625fbf Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 12 Aug 2008 21:31:39 -0700 Subject: [PATCH 04/27] Fix a spurious non-local net. During elaboration of continuous assignment that connected the rval to the lval with a part select forgot to mark the signal it created as temporary. --- elaborate.cc | 1 + netlist.cc | 2 ++ 2 files changed, 3 insertions(+) diff --git a/elaborate.cc b/elaborate.cc index fab58d9e9..82c052e74 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -164,6 +164,7 @@ 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; diff --git a/netlist.cc b/netlist.cc index 51cf898f6..462947d52 100644 --- a/netlist.cc +++ b/netlist.cc @@ -2295,6 +2295,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) From 3def0e0dec933a8a3685be4a0fafe0143914b732 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 12 Aug 2008 21:32:21 -0700 Subject: [PATCH 05/27] Fix some expression elaborate vector width problems. --- elab_expr.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/elab_expr.cc b/elab_expr.cc index 2939b91d9..8d7392d39 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -179,6 +179,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; @@ -247,6 +254,8 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des, } 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); @@ -1932,6 +1941,9 @@ NetETernary*PETernary::elaborate_expr(Design*des, NetScope*scope, return 0; } + /* Make sure the condition expression reduces to a single bit. */ + con = condition_reduce(con); + /* Whatever the width we choose for the ternary operator, we need to make sure the operands match. */ tru = pad_to_width(tru, expr_wid); From 50c1533fddc169d2421978f283837ad5242af0db Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 13 Aug 2008 22:22:59 -0700 Subject: [PATCH 06/27] Fix evaluation of logical equality with x bits. Logical (in)equality needs to look at all the bits of both operands, and cannot short circuit the test unless defined bits differ. If there are undefined bits, the equality is undefined at that point, but return x only if there are not other bits that make the results clearly unequal. --- eval_tree.cc | 19 ++++++++++++++++--- vvp/vthread.cc | 11 +++-------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/eval_tree.cc b/eval_tree.cc index 7cc7b9ac8..4a831ce2f 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -561,6 +561,13 @@ NetEConst* NetEBComp::eval_gteq_() } } +/* + * Evaluate == or !=. 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_(bool ne_flag) { NetEConst*l = dynamic_cast(left_); @@ -581,11 +588,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: @@ -597,17 +607,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) { diff --git a/vvp/vthread.cc b/vvp/vthread.cc index b83cfc397..2703bccb0 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -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); } } From 4b646aca9098222a3d9f6c636bc75b0ad4f757e6 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 14 Aug 2008 20:37:04 -0700 Subject: [PATCH 07/27] Account for signed multiply When multiply is done in native words, the conversion to words from the vp_vector4_t vectors must be done signed. This only matters if the input operands are different sizes (and themselves signed) but will not hurt even if we want an unsigned result. --- vvp/arith.cc | 111 +++------------------------------------------------ 1 file changed, 6 insertions(+), 105 deletions(-) diff --git a/vvp/arith.cc b/vvp/arith.cc index 0afea9c29..698e06b94 100644 --- a/vvp/arith.cc +++ b/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) From 61b9c5e0697c2c3118ab31eea6710e5913d9bd5e Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 14 Aug 2008 20:38:34 -0700 Subject: [PATCH 08/27] Pad signed expressions in continuous asignments When the continuous assignment is signed, then sign-extend the r-value in the few cases where the expression is stubbornly smaller then the desired width. --- elaborate.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index 82c052e74..fd77cf2f7 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -150,8 +150,12 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const (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 From 1ae2c0c9e0bb3134f81a051f31ce369926dd7ddd Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 15 Aug 2008 21:19:04 -0700 Subject: [PATCH 09/27] Extra diagnostic details in elaboration of continuous assignment. --- elaborate.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/elaborate.cc b/elaborate.cc index fd77cf2f7..9254a889c 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -122,7 +122,8 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const if (debug_elaborate) { cerr << get_fileline() << ": debug: PGAssign: elaborated r-value" << " width="<< rval->vector_width() - << ", type="<< rval->data_type() << endl; + << ", type="<< rval->data_type() + << ", expr=" << *rval_expr << endl; } assert(lval && rval); From 30e6cfce41ee14a95e31d2f8ae83dfd880243dcd Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 15 Aug 2008 22:03:19 -0700 Subject: [PATCH 10/27] Real valued nets are signed, and pform unary expression have width. Real valued nets should ne treated as signed no matter what. Also, PEUnary nary expressions need a useful test_width method. --- PExpr.h | 4 ++++ elab_expr.cc | 19 +++++++++++++++++++ netlist.cc | 5 ++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/PExpr.h b/PExpr.h index 08dccdd29..eef09b5f1 100644 --- a/PExpr.h +++ b/PExpr.h @@ -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, diff --git a/elab_expr.cc b/elab_expr.cc index 8d7392d39..2af5b86f8 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1954,6 +1954,25 @@ 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; + default: + return expr_->test_width(des, scope, min, lval, unsized_flag); + } +} + + NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, int expr_wid, bool) const { diff --git a/netlist.cc b/netlist.cc index 462947d52..273b6af28 100644 --- a/netlist.cc +++ b/netlist.cc @@ -604,7 +604,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) From 5ddf34d39bd1830617ac87268dd488a86f7a4ff5 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 16 Aug 2008 15:36:14 -0700 Subject: [PATCH 11/27] Signed operands do not make power (**) real. --- net_expr.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net_expr.cc b/net_expr.cc index 92594ea3d..4c15ddd7d 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -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; } From d2eba7eefe5b47093f691cd9f13bbcc138a50ad9 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 16 Aug 2008 16:25:56 -0700 Subject: [PATCH 12/27] Modulus value bit width should match input dividend width. --- vvp/vvp_net.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index a8c669e26..d922bb77d 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -1812,7 +1812,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, From f8bd8e1bd61a86a42e875cc2f996155214763bac Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 16 Aug 2008 17:30:32 -0700 Subject: [PATCH 13/27] Unary minus and signed right shift need to extend their arguments. In signed contextx, the right shift and unary minus expressions need to be sign extended before they operate, otherwise there may be bad results in the high bits in the greater context. --- elab_expr.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/elab_expr.cc b/elab_expr.cc index 2af5b86f8..fd033ab33 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -263,6 +263,8 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des, case 'r': // >> case 'R': // >>> + if (expr_wid > 0) + lp = pad_to_width(lp, expr_wid); tmp = new NetEBShift(op_, lp, rp); tmp->set_line(*this); break; @@ -2030,6 +2032,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); } From 66bed241f1da7a658f1ef45a690b705a3fa39bd0 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 16 Aug 2008 18:30:07 -0700 Subject: [PATCH 14/27] Prevent silent overflow of mantissa When converting a binary constant to a real value in the vvp code generator, make sure the mantissa does not overflow. If it does, panic in some way. --- tgt-vvp/eval_real.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index 8a7dda0f2..15322cdbc 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -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; } From e8804500b012736ce6393182975bcbfc4b5d71a8 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 16 Aug 2008 19:02:09 -0700 Subject: [PATCH 15/27] Replace an assert in vvp/arith.cc with a detailed message. ... and an assert. --- vvp/arith.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vvp/arith.cc b/vvp/arith.cc index 698e06b94..9a2061504 100644 --- a/vvp/arith.cc +++ b/vvp/arith.cc @@ -602,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); From a8ad505af78289a44350a0dbfa1441c1ecf5e92e Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 17 Aug 2008 08:21:24 -0700 Subject: [PATCH 16/27] Various improgements to expression ::synthesize methods Since NetExpr::synthesize methods were rarely used, then had a lot of bugs. Now that continuous assign uses these methods, these bugs must be fixed. Binary and Unary minus properly pad/extens its arguments, Case compare generates correct code, Divide properly takes on signed flag, Signed right shift sign-extends its argument to prevent loss of sign bits and uses the NetSignExtend instead of simple padding, Use the correct target node for reduction NAND, Properly handle constant arguments of NetESelect Handle some exressions that were not handled before, include abs() and POW. --- expr_synth.cc | 215 +++++++++++++++++++++++++++++++++++++++++--------- netmisc.cc | 44 +++++++++++ netmisc.h | 6 ++ 3 files changed, 226 insertions(+), 39 deletions(-) diff --git a/expr_synth.cc b/expr_synth.cc index e9c5d3085..9f129c37e 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -91,7 +91,7 @@ NetNet* NetExpr::synthesize(Design*des, NetScope*scope) */ NetNet* NetEBAdd::synthesize(Design*des, NetScope*scope) { - assert((op()=='+') || (op()=='-')); + ivl_assert(*this, (op()=='+') || (op()=='-')); NetNet *lsig=0, *rsig=0; bool real_args=false; @@ -220,8 +220,14 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope) width = lsig->vector_width(); if (rsig->vector_width() > width) width = rsig->vector_width(); - lsig = pad_to_width(des, lsig, width); - rsig = pad_to_width(des, rsig, width); + if (lsig->get_signed()) + lsig = pad_to_width_signed(des, lsig, width); + else + lsig = pad_to_width(des, lsig, width); + if (rsig->get_signed()) + rsig = pad_to_width_signed(des, rsig, width); + else + rsig = pad_to_width(des, rsig, width); } NetNet*osig = new NetNet(scope, scope->local_symbol(), @@ -231,10 +237,30 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope) osig->data_type(IVL_VT_LOGIC); bool signed_compare = lsig->get_signed() && rsig->get_signed(); + if (debug_elaborate) { + cerr << get_fileline() << ": debug: Comparison (" << op_ << ")" + << " is " << (signed_compare? "signed" : "unsigned") + << endl; + cerr << get_fileline() << ": : lsig is " + << (lsig->get_signed()? "signed" : "unsigned") + << " rsig is " << (rsig->get_signed()? "signed" : "unsigned") + << endl; + } + + if (op_ == 'E' || op_ == 'N') { + NetCaseCmp*gate = new NetCaseCmp(scope, scope->local_symbol(), + width, op_=='E'?true:false); + gate->set_line(*this); + connect(gate->pin(0), osig->pin(0)); + connect(gate->pin(1), lsig->pin(0)); + connect(gate->pin(2), rsig->pin(0)); + des->add_node(gate); + return osig; + } /* Handle the special case of a single bit equality operation. Make an XNOR gate instead of a comparator. */ - if ((width == 1) && ((op_ == 'e') || (op_ == 'E')) && !real_args) { + if ((width == 1) && (op_ == 'e') && !real_args) { NetLogic*gate = new NetLogic(scope, scope->local_symbol(), 3, NetLogic::XNOR, 1); gate->set_line(*this); @@ -248,7 +274,7 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope) /* Handle the special case of a single bit inequality operation. This is similar to single bit equality, but uses an XOR instead of an XNOR gate. */ - if ((width == 1) && ((op_ == 'n') || (op_ == 'N')) && !real_args) { + if ((width == 1) && (op_ == 'n') && !real_args) { NetLogic*gate = new NetLogic(scope, scope->local_symbol(), 3, NetLogic::XOR, 1); gate->set_line(*this); @@ -404,6 +430,7 @@ NetNet* NetEBDiv::synthesize(Design*des, NetScope*scope) NetNet::IMPLICIT, width); osig->set_line(*this); osig->data_type(lsig->data_type()); + osig->set_signed(has_sign()); osig->local_flag(true); switch (op()) { @@ -414,6 +441,7 @@ NetNet* NetEBDiv::synthesize(Design*des, NetScope*scope) lsig->vector_width(), rsig->vector_width()); div->set_line(*this); + div->set_signed(has_sign()); des->add_node(div); connect(div->pin_DataA(), lsig->pin(0)); @@ -552,8 +580,8 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope) return 0; } - bool right_flag = op_ == 'r' || op_ == 'R'; - bool signed_flag = op_ == 'R'; + const bool right_flag = op_ == 'r' || op_ == 'R'; + const bool signed_flag = op_ == 'R'; /* Detect the special case where the shift amount is constant. Evaluate the shift amount, and simply reconnect @@ -562,7 +590,7 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope) verinum shift_v = rcon->value(); long shift = shift_v.as_long(); - if (op() == 'r') + if (right_flag) shift = 0-shift; if (shift == 0) @@ -575,34 +603,13 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope) // ushift is the amount of pad created by the shift. unsigned long ushift = shift>=0? shift : -shift; - if (ushift > osig->vector_width()) - ushift = osig->vector_width(); + ivl_assert(*this, ushift < osig->vector_width()); // part_width is the bits of the vector that survive the shift. unsigned long part_width = osig->vector_width() - ushift; - verinum znum (verinum::V0, ushift, true); - NetConst*zcon = new NetConst(scope, scope->local_symbol(), - znum); - des->add_node(zcon); - - /* Detect the special case that the shift is the size of - the whole expression. Simply connect the pad to the - osig and escape. */ - if (ushift >= osig->vector_width()) { - connect(zcon->pin(0), osig->pin(0)); - return osig; - } - - NetNet*zsig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, znum.len()); - zsig->data_type(osig->data_type()); - zsig->local_flag(true); - zsig->set_line(*this); - connect(zcon->pin(0), zsig->pin(0)); - - /* Create a part select to reduce the width of the lsig - to the amount left by the shift. */ + // Create a part select to reduce the width of the lsig + // to the amount left by the shift. NetPartSelect*psel = new NetPartSelect(lsig, shift<0? ushift : 0, part_width, NetPartSelect::VP); @@ -615,6 +622,34 @@ NetNet* NetEBShift::synthesize(Design*des, NetScope*scope) psig->set_line(*this); connect(psig->pin(0), psel->pin(0)); + // Handle the special case of a signed right shift. In + // this case, use the NetSignExtend device to pad the + // result to the desired width. + if (signed_flag && right_flag) { + NetSignExtend*pad = new NetSignExtend(scope, scope->local_symbol(), + osig->vector_width()); + des->add_node(pad); + pad->set_line(*this); + + connect(pad->pin(1), psig->pin(0)); + connect(pad->pin(0), osig->pin(0)); + return osig; + } + + // Other cases are handled by zero-extending on the + // proper end. + verinum znum (verinum::V0, ushift, true); + NetConst*zcon = new NetConst(scope, scope->local_symbol(), + znum); + des->add_node(zcon); + + NetNet*zsig = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, znum.len()); + zsig->data_type(osig->data_type()); + zsig->local_flag(true); + zsig->set_line(*this); + connect(zcon->pin(0), zsig->pin(0)); + NetConcat*ccat = new NetConcat(scope, scope->local_symbol(), osig->vector_width(), 2); ccat->set_line(*this); @@ -674,7 +709,7 @@ NetNet* NetEConcat::synthesize(Design*des, NetScope*scope) if (flag == false) return 0; - assert(tmp[0]); + ivl_assert(*this, tmp[0]); /* Make a NetNet object to carry the output vector. */ perm_string path = scope->local_symbol(); @@ -692,7 +727,9 @@ NetNet* NetEConcat::synthesize(Design*des, NetScope*scope) unsigned cur_pin = 1; for (unsigned rpt = 0; rpt < repeat(); rpt += 1) { for (unsigned idx = 0 ; idx < parms_.count() ; idx += 1) { - connect(concat->pin(cur_pin), tmp[parms_.count()-idx-1]->pin(0)); + unsigned concat_item = parms_.count()-idx-1; + ivl_assert(*this, tmp[concat_item]); + connect(concat->pin(cur_pin), tmp[concat_item]->pin(0)); cur_pin += 1; } } @@ -787,9 +824,28 @@ NetNet* NetEUnary::synthesize(Design*des, NetScope*scope) return expr_->synthesize(des, scope); if (op_ == '-') { - NetExpr*tmp = make_sub_expr(0, expr_); - NetNet*sig = tmp->synthesize(des, scope); - delete tmp; + NetNet*sig = expr_->synthesize(des, scope); + sig = sub_net_from(des, scope, 0, sig); + return sig; + } + + if (op_ == 'm') { + NetNet*sub = expr_->synthesize(des, scope); + if (expr_->has_sign() == false) + return sub; + + NetNet*sig = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, sub->vector_width()); + sig->set_line(*this); + sig->local_flag(true); + sig->data_type(sub->data_type()); + + NetAbs*tmp = new NetAbs(scope, scope->local_symbol(), sub->vector_width()); + des->add_node(tmp); + tmp->set_line(*this); + + connect(tmp->pin(1), sub->pin(0)); + connect(tmp->pin(0), sig->pin(0)); return sig; } @@ -835,7 +891,7 @@ NetNet* NetEUReduce::synthesize(Design*des, NetScope*scope) rtype = NetUReduce::XOR; break; case 'A': - rtype = NetUReduce::XNOR; + rtype = NetUReduce::NAND; break; case 'X': rtype = NetUReduce::XNOR; @@ -857,6 +913,14 @@ NetNet* NetEUReduce::synthesize(Design*des, NetScope*scope) return osig; } +/* + * Turn a part/bit select expression into gates. + * We know some things about the expression that elaboration enforces + * for us: + * + * - Expression elaboration already converted the offset expression into + * cannonical form, so we don't have to worry about that here. + */ NetNet* NetESelect::synthesize(Design *des, NetScope*scope) { @@ -866,6 +930,79 @@ NetNet* NetESelect::synthesize(Design *des, NetScope*scope) NetNet*off = 0; + // Detect the special case that there is a base expression and + // it is constant. In this case we can generate fixed part selects. + if (NetEConst*base_const = dynamic_cast(base_)) { + verinum base_tmp = base_const->value(); + ivl_assert(*this, base_tmp.is_defined()); + + long base_val = base_tmp.as_long(); + unsigned select_width = expr_width(); + + // Any below X bits? + NetNet*below = 0; + if (base_val < 0) { + unsigned below_width = abs(base_val); + base_val = 0; + ivl_assert(*this, below_width < select_width); + select_width -= below_width; + + below = make_const_x(des, scope, below_width); + below->set_line(*this); + } + + // Any above bits?. + NetNet*above = 0; + if (base_val+select_width > sub->vector_width()) { + select_width = sub->vector_width() - base_val; + unsigned above_width = expr_width() - select_width; + + above = make_const_x(des, scope, above_width); + above->set_line(*this); + } + + // Make the make part select. + NetPartSelect*sel = new NetPartSelect(sub, base_val, select_width, + NetPartSelect::VP); + des->add_node(sel); + + NetNet*tmp = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, select_width); + tmp->data_type(sub->data_type()); + tmp->local_flag(true); + tmp->set_line(*this); + connect(sel->pin(0), tmp->pin(0)); + + unsigned concat_count = 1; + if (above) + concat_count += 1; + if (below) + concat_count += 1; + if (concat_count > 1) { + NetConcat*cat = new NetConcat(scope, scope->local_symbol(), + expr_width(), concat_count); + cat->set_line(*this); + des->add_node(cat); + if (below) { + connect(cat->pin(1), below->pin(0)); + connect(cat->pin(2), tmp->pin(0)); + } else { + connect(cat->pin(1), tmp->pin(0)); + } + if (above) { + connect(cat->pin(concat_count), above->pin(0)); + } + + tmp = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, expr_width()); + tmp->data_type(sub->data_type()); + tmp->local_flag(true); + tmp->set_line(*this); + connect(cat->pin(0), tmp->pin(0)); + } + return tmp; + } + // This handles the case that the NetESelect exists to do an // actual part/bit select. Generate a NetPartSelect object to // do the work, and replace "sub" with the selected output. @@ -977,7 +1114,7 @@ NetNet* NetETernary::synthesize(Design *des, NetScope*scope) perm_string path = csig->scope()->local_symbol(); - assert(csig->vector_width() == 1); + ivl_assert(*this, csig->vector_width() == 1); unsigned width=expr_width(); NetNet*osig = new NetNet(csig->scope(), path, NetNet::IMPLICIT, width); diff --git a/netmisc.cc b/netmisc.cc index e6e6e5659..d4c77956f 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -76,6 +76,36 @@ NetNet* add_to_net(Design*des, NetNet*sig, long val) #endif } +NetNet* sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig) +{ + verinum zero ((uint64_t)0, sig->vector_width()); + NetConst*zero_obj = new NetConst(scope, scope->local_symbol(), zero); + des->add_node(zero_obj); + + NetNet*zero_net = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, sig->vector_width()); + zero_net->data_type(sig->data_type()); + zero_net->local_flag(true); + + connect(zero_net->pin(0), zero_obj->pin(0)); + + NetAddSub*adder = new NetAddSub(scope, scope->local_symbol(), sig->vector_width()); + des->add_node(adder); + adder->attribute(perm_string::literal("LPM_Direction"), verinum("SUB")); + + connect(zero_net->pin(0), adder->pin_DataA()); + connect(adder->pin_DataB(), sig->pin(0)); + + NetNet*tmp = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, sig->vector_width()); + tmp->data_type(sig->data_type()); + tmp->local_flag(true); + + connect(adder->pin_Result(), tmp->pin(0)); + + return tmp; +} + NetNet* cast_to_int(Design*des, NetScope*scope, NetNet*src, unsigned wid) { if (src->data_type() != IVL_VT_REAL) @@ -170,6 +200,20 @@ NetEConst* make_const_x(unsigned long wid) return resx; } +NetNet* make_const_x(Design*des, NetScope*scope, unsigned long wid) +{ + verinum xxx (verinum::Vx, wid); + NetConst*res = new NetConst(scope, scope->local_symbol(), xxx); + des->add_node(res); + + NetNet*sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, wid); + sig->local_flag(true); + sig->data_type(IVL_VT_LOGIC); + + connect(sig->pin(0), res->pin(0)); + return sig; +} + NetExpr* condition_reduce(NetExpr*expr) { if (expr->expr_width() == 1) diff --git a/netmisc.h b/netmisc.h index 7d1b42a90..af954ebf9 100644 --- a/netmisc.h +++ b/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 @@ -114,6 +115,11 @@ extern NetExpr*make_sub_expr(long val, NetExpr*expr); */ extern NetEConst*make_const_x(unsigned long wid); +/* + * Make A const net + */ +extern NetNet* make_const_x(Design*des, NetScope*scope, unsigned long wid); + /* * In some cases the lval is accessible as a pointer to the head of * a list of NetAssign_ objects. This function returns the width of From 0de2dcb211efece6f78ba279827cdc5957367b0a Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 17 Aug 2008 08:22:42 -0700 Subject: [PATCH 17/27] Allow elaborate_expr to handle implicit nets. When the elaborate_expr code is used for expressions of continuous assignments, it needs to be able to create implicit nets. --- elab_expr.cc | 16 ++++++++++++++++ elaborate.cc | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/elab_expr.cc b/elab_expr.cc index fd033ab33..76d966130 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1078,6 +1078,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. diff --git a/elaborate.cc b/elaborate.cc index 9254a889c..213f66443 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3494,6 +3494,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 @@ -3558,6 +3559,7 @@ bool Module::elaborate(Design*des, NetScope*scope) const // complex. const list&gl = get_gates(); + error_implicit = false; for (list::const_iterator gt = gl.begin() ; gt != gl.end() ; gt ++ ) { @@ -3565,6 +3567,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. From e18eb32d8baf8f2a5c4227a73ead8c836455ace6 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 20 Aug 2008 21:47:07 -0700 Subject: [PATCH 18/27] Process shift by constant amounts early in expression elaboration. The expr:::synthesize methods need not deal with saturating left or right shifts if they are dealt with early, in elaborate_expr methods. So the elaborate_expr for shift takes on much more responsibility. --- PExpr.h | 3 + Statement.h | 1 + elab_expr.cc | 244 +++++++++++++++++++++++++++++++++++++++------------ elaborate.cc | 46 +++++----- netmisc.cc | 7 ++ netmisc.h | 1 + 6 files changed, 225 insertions(+), 77 deletions(-) diff --git a/PExpr.h b/PExpr.h index eef09b5f1..a06a59015 100644 --- a/PExpr.h +++ b/PExpr.h @@ -579,6 +579,9 @@ 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; + static void suppress_operand_sign_if_needed_(NetExpr*lp, NetExpr*rp); private: diff --git a/Statement.h b/Statement.h index 5bca41739..bdf4e07f4 100644 --- a/Statement.h +++ b/Statement.h @@ -101,6 +101,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_; diff --git a/elab_expr.cc b/elab_expr.cc index 76d966130..2258ef78c 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -147,8 +147,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; @@ -209,64 +209,12 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des, break; case 'l': // << - if (NetEConst*lpc = dynamic_cast (lp)) { - if (NetEConst*rpc = dynamic_cast (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. - if (expr_wid >= 0) - lp = pad_to_width(lp, expr_wid); - 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': // >>> - if (expr_wid > 0) - lp = pad_to_width(lp, expr_wid); - tmp = new NetEBShift(op_, lp, rp); - tmp->set_line(*this); + tmp = elaborate_expr_base_rshift_(des, lp, rp, expr_wid); break; case '^': @@ -333,6 +281,190 @@ 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; + + if (NetEConst*lpc = dynamic_cast (lp)) { + if (NetEConst*rpc = dynamic_cast (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 if (NetEConst*rpc = dynamic_cast (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 (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; +} + unsigned PEBComp::test_width(Design*, NetScope*,unsigned, unsigned, bool&) const { return 1; diff --git a/elaborate.cc b/elaborate.cc index 213f66443..23ce93fff 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1584,6 +1584,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 @@ -1665,23 +1688,9 @@ 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); - /* Rewrite delayed assignments as assignments that are delayed. For example, a = # b; becomes: @@ -1802,12 +1811,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 diff --git a/netmisc.cc b/netmisc.cc index d4c77956f..5d15f4085 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -200,6 +200,13 @@ 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); diff --git a/netmisc.h b/netmisc.h index af954ebf9..cc6f9a7fe 100644 --- a/netmisc.h +++ b/netmisc.h @@ -114,6 +114,7 @@ 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 From 65a4f36de5f682783468deea19a14b2406c21ae4 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 21 Aug 2008 18:58:38 -0700 Subject: [PATCH 19/27] Watch out for left operand of left shift that is not known early. It is possible for the left operand of a left shift to be not known early during elaborate expression. In that case, make a punt expression and expect it to be resolved later. --- elab_expr.cc | 14 ++++++++++++++ pform_dump.cc | 3 +++ 2 files changed, 17 insertions(+) diff --git a/elab_expr.cc b/elab_expr.cc index c496b04de..d9a693711 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -287,6 +287,20 @@ NetExpr* PEBinary::elaborate_expr_base_lshift_(Design*des, { 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*lpc = dynamic_cast (lp)) { if (NetEConst*rpc = dynamic_cast (rp)) { // Handle the super-special case that both diff --git a/pform_dump.cc b/pform_dump.cc index f506bd655..3dae41844 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -274,6 +274,9 @@ void PEBinary::dump(ostream&out) const case 'l': out << "<<"; break; + case 'L': + out << "<="; + break; case 'n': out << "!="; break; From 65c3bc91de97c06f511cd919998fa72edee60f48 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 23 Aug 2008 10:50:24 -0700 Subject: [PATCH 20/27] Short-circuit elaboration of ternary expressions. When the condition expression of a ternary is constant 1 or 0, we can short-circuit the elaboration by only processing the clause (true or false) that we need. This saves compile time and execution time. --- PExpr.h | 2 +- elab_expr.cc | 48 +++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/PExpr.h b/PExpr.h index fdb0d725f..e58eae287 100644 --- a/PExpr.h +++ b/PExpr.h @@ -686,7 +686,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; diff --git a/elab_expr.cc b/elab_expr.cc index d9a693711..886a1a6ab 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -2060,7 +2060,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_); @@ -2079,17 +2079,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 (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; @@ -2105,9 +2142,6 @@ NetETernary*PETernary::elaborate_expr(Design*des, NetScope*scope, return 0; } - /* Make sure the condition expression reduces to a single bit. */ - con = condition_reduce(con); - /* Whatever the width we choose for the ternary operator, we need to make sure the operands match. */ tru = pad_to_width(tru, expr_wid); From 03416793602eec600edbc9170146daa18ea0fea1 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 23 Aug 2008 18:11:11 -0700 Subject: [PATCH 21/27] Handle real-valued unary subtract. the sub_net_from function is used by the ::synthesize method of the NetEUnary class to make the expression 0-N. By making that function handle a real-valued net, the NetEUnary suddenly supports real-valued nets, and this probably helps in other places as well. --- netmisc.cc | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/netmisc.cc b/netmisc.cc index 5d15f4085..c0f1d2c0a 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -78,16 +78,26 @@ NetNet* add_to_net(Design*des, NetNet*sig, long val) NetNet* sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig) { - verinum zero ((uint64_t)0, sig->vector_width()); - NetConst*zero_obj = new NetConst(scope, scope->local_symbol(), zero); - des->add_node(zero_obj); - NetNet*zero_net = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, sig->vector_width()); zero_net->data_type(sig->data_type()); zero_net->local_flag(true); - connect(zero_net->pin(0), zero_obj->pin(0)); + 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); From c26ee8534d5181e537f6baafe2e792f7169d5abe Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 25 Aug 2008 21:52:40 -0700 Subject: [PATCH 22/27] Improved comments. --- PExpr.h | 3 ++- netmisc.h | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/PExpr.h b/PExpr.h index e58eae287..e424355f2 100644 --- a/PExpr.h +++ b/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. // @@ -581,6 +581,7 @@ class PEBinary : public PExpr { 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); diff --git a/netmisc.h b/netmisc.h index cc6f9a7fe..f54237b03 100644 --- a/netmisc.h +++ b/netmisc.h @@ -137,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, From b2b0f45473195a372c11271c907e4db125eefc25 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 26 Aug 2008 21:33:24 -0700 Subject: [PATCH 23/27] Use the expression with to calculate expression width in assignments. In continuous assignment, the width of the expression needs to come from the expression itself, and not just from the width of the l-value. Use the PExpr::test_width method to get the width of the expression to pass to the elaborate. --- elab_expr.cc | 146 +++++++++++++++++++++++++++++++++++++-------------- elaborate.cc | 17 ++++-- 2 files changed, 121 insertions(+), 42 deletions(-) diff --git a/elab_expr.cc b/elab_expr.cc index 886a1a6ab..73d0a3a27 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -229,11 +229,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': /* === */ @@ -301,6 +297,12 @@ NetExpr* PEBinary::elaborate_expr_base_lshift_(Design*des, 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 (lp)) { if (NetEConst*rpc = dynamic_cast (rp)) { // Handle the super-special case that both @@ -313,16 +315,17 @@ NetExpr* PEBinary::elaborate_expr_base_lshift_(Design*des, // 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) + if (expr_wid > 0 && expr_wid > use_len) use_len = expr_wid; - result = verinum(result, lpval.len()); + result = verinum(result, use_len); } tmp = new NetEConst(result); if (debug_elaborate) cerr << get_fileline() << ": debug: " - << "Precalculate " << *this - << " to constant " << *tmp << endl; + << "Precalculate " << *lpc << " << " << shift + << " to constant " << *tmp + << " (expr_wid=" << expr_wid << ")" << endl; } else { // Handle the special case that the left @@ -479,6 +482,19 @@ NetExpr* PEBinary::elaborate_expr_base_rshift_(Design*des, 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; @@ -532,6 +548,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; } @@ -1096,36 +1117,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 (ex1); + const NetEConst*ex2_const = dynamic_cast (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; @@ -2165,9 +2220,22 @@ unsigned PEUnary::test_width(Design*des, NetScope*scope, case 'N': // Reduction NOR (~|) case 'X': // Reduction NXOR (~^) return 1; - default: - return expr_->test_width(des, scope, min, lval, unsized_flag); } + + 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; } diff --git a/elaborate.cc b/elaborate.cc index deaa14d1a..c2fe3099d 100644 --- a/elaborate.cc +++ b/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,9 +99,20 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const << ", type=" << lval->data_type() << endl; } + bool unsized_flag = false; + unsigned use_width = pin(1)->test_width(des, scope, lval->vector_width(), + lval->vector_width(), unsized_flag); + + 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; + } + + int expr_wid = unsized_flag? -1 : use_width; NetExpr*rval_expr = elab_and_eval(des, scope, pin(1), - lval->vector_width(), - lval->vector_width()); + expr_wid, lval->vector_width()); if (rval_expr == 0) { cerr << get_fileline() << ": error: Unable to elaborate r-value: " From e6c26373674a17c21d9b98b478f8e10ce9c83ebf Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 28 Aug 2008 21:15:43 -0700 Subject: [PATCH 24/27] Clean up $clog2() measurement of unsized numbers. If the argument to $clog2() is unsized constant, then trim it to the smallest representation that doesn't lose the sign, then do the $clog2 on that. Also, use integer_width instead of 32 for the minimum $clog2() result for a negative value. --- eval_tree.cc | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/eval_tree.cc b/eval_tree.cc index 422e14f48..ad203e8fe 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -1627,7 +1627,6 @@ NetExpr* evaluate_clog2(NetExpr*arg) { NetEConst*tmpi = dynamic_cast(arg); NetECReal*tmpr = dynamic_cast(arg); - bool is_neg = false; if (tmpi || tmpr) { verinum arg; if (tmpi) { @@ -1644,9 +1643,17 @@ NetExpr* evaluate_clog2(NetExpr*arg) return rtn; } + bool is_neg = false; uint64_t res = 0; - if (arg.is_negative()) is_neg = true; + if (arg.is_negative()) { + is_neg = true; + // If the length is not defined, then work with + // the trimmed version of the number. + if (! arg.has_len()) + arg = trim_vnum(arg); + } arg.has_sign(false); // $unsigned() + if (!arg.is_zero()) { arg = arg - verinum((uint64_t)1, 1); while (!arg.is_zero()) { @@ -1654,9 +1661,11 @@ NetExpr* evaluate_clog2(NetExpr*arg) arg = arg >> 1; } } - if (is_neg && res < 32) res = 32; + + if (is_neg && res < integer_width) + res = integer_width; + verinum tmp (res, 32); - tmp.has_sign(true); NetEConst*rtn = new NetEConst(tmp); return rtn; } From 5d5228b6b8eadef99631ea6ac4aebcd129ab0407 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 28 Aug 2008 21:16:44 -0700 Subject: [PATCH 25/27] Minor improvements to expression debug prints. --- design_dump.cc | 2 ++ pform_dump.cc | 3 +++ verinum.cc | 12 ++++++++---- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/design_dump.cc b/design_dump.cc index 1af627745..82f1f35bf 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1015,6 +1015,8 @@ void NetScope::dump(ostream&o) const ; pp != parameters.end() ; pp ++) { o << " parameter "; + o << pp->second.type << " "; + if ((*pp).second.signed_flag) o << "signed "; diff --git a/pform_dump.cc b/pform_dump.cc index 3dae41844..729a30819 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -283,6 +283,9 @@ void PEBinary::dump(ostream&out) const case 'N': out << "!=="; break; + case 'p': + out << "**"; + break; case 'R': out << ">>>"; break; diff --git a/verinum.cc b/verinum.cc index b4f20f32e..76c3fb75d 100644 --- a/verinum.cc +++ b/verinum.cc @@ -691,11 +691,15 @@ ostream& operator<< (ostream&o, const verinum&v) verinum::V trim_left = v.get(v.len()-1); unsigned idx; - for (idx = v.len()-1; idx > 0; idx -= 1) - if (trim_left != v.get(idx-1)) - break; + if (v.has_sign()) { + for (idx = v.len()-1; idx > 0; idx -= 1) + if (trim_left != v.get(idx-1)) + break; - o << trim_left; + o << trim_left; + } else { + idx = v.len(); + } while (idx > 0) { o << v.get(idx-1); From 4c7144afc08559c97bb0b8131f82bfe56d935c2d Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 28 Aug 2008 22:08:46 -0700 Subject: [PATCH 26/27] Remove dead EEQ code. The EEQ function is handled by vvp_cmp_eeq, an arithmetic expression processor and the logic version of EEQ is never used. --- vvp/logic.cc | 32 -------------------------------- vvp/logic.h | 11 ----------- 2 files changed, 43 deletions(-) diff --git a/vvp/logic.cc b/vvp/logic.cc index ecfc947d7..3ba7c965b 100644 --- a/vvp/logic.cc +++ b/vvp/logic.cc @@ -109,35 +109,6 @@ void vvp_fun_and::run_run() vvp_send_vec4(ptr->out, result); } -vvp_fun_eeq::vvp_fun_eeq(unsigned wid, bool invert) -: vvp_fun_boolean_(wid), invert_(invert) -{ - count_functors_logic += 1; -} - -vvp_fun_eeq::~vvp_fun_eeq() -{ -} - -void vvp_fun_eeq::run_run() -{ - vvp_net_t*ptr = net_; - net_ = 0; - - vvp_vector4_t result (input_[0]); - - for (unsigned idx = 0 ; idx < result.size() ; idx += 1) { - vvp_bit4_t bitbit = result.value(idx); - bitbit = (bitbit == input_[1].value(idx))? BIT4_1 : BIT4_0; - if (invert_) - bitbit = ~bitbit; - - result.set_bit(idx, bitbit); - } - - vvp_send_vec4(ptr->out, result); -} - vvp_fun_buf::vvp_fun_buf() { net_ = 0; @@ -579,9 +550,6 @@ void compile_functor(char*label, char*type, unsigned width, } else if (strcmp(type, "RPMOS") == 0) { obj = new vvp_fun_rpmos(false); - } else if (strcmp(type, "EEQ") == 0) { - obj = new vvp_fun_eeq(width, false); - } else if (strcmp(type, "NOT") == 0) { obj = new vvp_fun_not(); diff --git a/vvp/logic.h b/vvp/logic.h index 24df457d2..841ce4aaa 100644 --- a/vvp/logic.h +++ b/vvp/logic.h @@ -52,17 +52,6 @@ class vvp_fun_and : public vvp_fun_boolean_ { bool invert_; }; -class vvp_fun_eeq : public vvp_fun_boolean_ { - - public: - explicit vvp_fun_eeq(unsigned wid, bool invert); - ~vvp_fun_eeq(); - - private: - void run_run(); - bool invert_; -}; - /* * The buffer functor is a very primitive functor that takes the input * from port-0 (and only port-0) and retransmits it as a vvp_vector4_t. From 6411e96193ba582f7846a171b895689435a8c971 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 6 Sep 2008 18:05:18 -0700 Subject: [PATCH 27/27] Generate delay devices for sign-extend devices. It is possible for signe-extend to have a delay attached to it. (Same for repeat.) Handle it like other LPM devices, by stuffing a .delay device into the output path of the device, if appropriate. --- design_dump.cc | 10 ++++++++-- tgt-vvp/vvp_scope.c | 10 +++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/design_dump.cc b/design_dump.cc index 25e61d04e..f17ee9605 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -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); } diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 89cc691a9..32780a41d 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -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))); }