From 1d884cb0e9348e3fcdc65df0f60dee00c8debbc8 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 10 Aug 2008 18:22:34 -0700 Subject: [PATCH 01/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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/93] 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))); } From 4898cd04c6c5546728a5f81c879fc82710e477dd Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 7 Sep 2008 16:43:54 -0700 Subject: [PATCH 28/93] Remove redundant back-end selections. Target selection is done by the DLL target code generator, so there is no value having a layer of target selection ahead of it. Remove all that redundant code and simplify the target config files to reflect this. --- Makefile.in | 2 +- emit.cc | 14 -------------- main.cc | 32 ++++++++++++++++---------------- t-dll.cc | 6 ++---- t-dll.h | 2 ++ target.h | 9 --------- targets.cc | 29 ----------------------------- tgt-null/null-s.conf | 1 - tgt-null/null.conf | 1 - tgt-stub/stub-s.conf | 1 - tgt-stub/stub.conf | 1 - tgt-vhdl/vhdl.conf | 1 - tgt-vvp/vvp-s.conf.in | 1 - tgt-vvp/vvp.conf.in | 1 - 14 files changed, 21 insertions(+), 80 deletions(-) delete mode 100644 targets.cc diff --git a/Makefile.in b/Makefile.in index 6fb8b38d1..e74325e6d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -110,7 +110,7 @@ net_proc.o net_scope.o net_tran.o net_udp.o pad_to_width.o \ parse.o parse_misc.o pform.o pform_analog.o pform_disciplines.o \ pform_dump.o pform_types.o \ set_width.o symbol_search.o sync.o sys_funcs.o \ -verinum.o verireal.o target.o targets.o \ +verinum.o verireal.o target.o \ Attrib.o HName.o LineInfo.o Module.o PDelays.o PEvent.o \ PExpr.o PGate.o PGenerate.o PScope.o PSpec.o \ PTask.o PUdp.o PFunction.o PWire.o Statement.o AStatement.o StringHeap.o \ diff --git a/emit.cc b/emit.cc index 785520a12..1370cb617 100644 --- a/emit.cc +++ b/emit.cc @@ -540,17 +540,3 @@ void NetEUnary::expr_scan(struct expr_scan_t*tgt) const { tgt->expr_unary(this); } - -int emit(const Design*des, const char*type) -{ - for (unsigned idx = 0 ; target_table[idx] ; idx += 1) { - const struct target*tgt = target_table[idx]; - if (strcmp(tgt->name, type) == 0) - return des->emit(tgt->meth); - - } - - cerr << "error: Code generator type " << type - << " not found." << endl; - return -1; -} diff --git a/main.cc b/main.cc index deaae3359..6cab41113 100644 --- a/main.cc +++ b/main.cc @@ -59,6 +59,7 @@ const char NOTICE[] = # include "target.h" # include "compiler.h" # include "discipline.h" +# include "t-dll.h" #if defined(__MINGW32__) && !defined(HAVE_GETOPT_H) extern "C" int getopt(int argc, char*argv[], const char*fmt); @@ -79,8 +80,6 @@ const char VERSION[] = "$Name: $"; const char*basedir = "."; -const char*target = "null"; - /* * These are the language support control flags. These support which * language features (the generation) to support. The generation_flag @@ -293,7 +292,7 @@ static void find_module_mention(map&check_map, PGenerate*s); * -T: * Select which expression to use. * - * -t: + * -t: (obsolete) * Usually, "-t:dll" * * basedir: @@ -483,7 +482,7 @@ static void read_iconfig_file(const char*ipath) library_suff.push_back(strdup(cp)); } else if (strcmp(buf,"-t") == 0) { - target = strdup(cp); + // NO LONGER USED } else if (strcmp(buf,"-T") == 0) { if (strcmp(cp,"min") == 0) { @@ -844,20 +843,21 @@ int main(int argc, char*argv[]) } if (verbose_flag) { - cout << "CODE GENERATION -t "< 0) { - cerr << "error: Code generation had " - << emit_rc << " errors." - << endl; - return 1; - } - if (emit_rc < 0) { - cerr << "error: Code generator failure: " << emit_rc << endl; - return -1; + if (int emit_rc = des->emit(&dll_target_obj)) { + if (emit_rc > 0) { + cerr << "error: Code generation had " + << emit_rc << " errors." + << endl; + return 1; + } + if (emit_rc < 0) { + cerr << "error: Code generator failure: " << emit_rc << endl; + return -1; + } + assert(emit_rc); } if (verbose_flag) { diff --git a/t-dll.cc b/t-dll.cc index 7e4f1714f..e171babdc 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -32,6 +32,8 @@ # include # include "ivl_assert.h" +struct dll_target dll_target_obj; + #if defined(__WIN32__) inline ivl_dll_t ivl_dlopen(const char *name) @@ -144,8 +146,6 @@ static perm_string make_scope_name(const hname_t&name) return lex_strings.make(buf); } -static struct dll_target dll_target_obj; - static void drive_from_link(const Link&lnk, ivl_drive_t&drv0, ivl_drive_t&drv1) { switch (lnk.drive0()) { @@ -2578,5 +2578,3 @@ bool dll_target::signal_paths(const NetNet*net) return true; } - -extern const struct target tgt_dll = { "dll", &dll_target_obj }; diff --git a/t-dll.h b/t-dll.h index e3646417b..d13d43ce8 100644 --- a/t-dll.h +++ b/t-dll.h @@ -178,6 +178,8 @@ struct dll_target : public target_t, public expr_scan_t { static ivl_expr_t expr_from_value_(const verinum&that); }; +extern struct dll_target dll_target_obj; + /* * These are various private declarations used by the t-dll target. */ diff --git a/target.h b/target.h index bed4815e6..a266d6d15 100644 --- a/target.h +++ b/target.h @@ -151,11 +151,6 @@ struct expr_scan_t { }; -/* The emit functions take a design and emit it to the output stream - using the specified target. If the target is given by name, it is - located in the target_table and used. */ -extern int emit(const Design*des, const char*type); - /* This function takes a fully qualified Verilog name (which may have, for example, dots in it) and produces a mangled version that can be used by most any language. */ @@ -165,8 +160,4 @@ extern string mangle(const string&str); used inside a string constant for a C++ compiler. */ extern string stresc(const string&str); -/* This is the table of supported output targets. It is a null - terminated array of pointers to targets. */ -extern const struct target *target_table[]; - #endif diff --git a/targets.cc b/targets.cc deleted file mode 100644 index 8df415cf3..000000000 --- a/targets.cc +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 1998 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 - * General Public License as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -# include "config.h" - -# include "target.h" - -extern const struct target tgt_dll; - -const struct target *target_table[] = { - &tgt_dll, - 0 -}; diff --git a/tgt-null/null-s.conf b/tgt-null/null-s.conf index bf62222dc..8f1cd19ea 100644 --- a/tgt-null/null-s.conf +++ b/tgt-null/null-s.conf @@ -1,5 +1,4 @@ functor:synth2 functor:synth functor:syn-rules --t:dll flag:DLL=null.tgt diff --git a/tgt-null/null.conf b/tgt-null/null.conf index 4d6369401..9d870274e 100644 --- a/tgt-null/null.conf +++ b/tgt-null/null.conf @@ -1,2 +1 @@ --t:dll flag:DLL=null.tgt diff --git a/tgt-stub/stub-s.conf b/tgt-stub/stub-s.conf index 190574ce0..193daf301 100644 --- a/tgt-stub/stub-s.conf +++ b/tgt-stub/stub-s.conf @@ -3,5 +3,4 @@ functor:synth functor:syn-rules functor:cprop functor:nodangle --t:dll flag:DLL=stub.tgt diff --git a/tgt-stub/stub.conf b/tgt-stub/stub.conf index 5c0c1c576..eb4cee787 100644 --- a/tgt-stub/stub.conf +++ b/tgt-stub/stub.conf @@ -1,4 +1,3 @@ functor:cprop functor:nodangle --t:dll flag:DLL=stub.tgt diff --git a/tgt-vhdl/vhdl.conf b/tgt-vhdl/vhdl.conf index b96c4c05e..0d382d395 100644 --- a/tgt-vhdl/vhdl.conf +++ b/tgt-vhdl/vhdl.conf @@ -1,4 +1,3 @@ functor:cprop functor:nodangle --t:dll flag:DLL=vhdl.tgt diff --git a/tgt-vvp/vvp-s.conf.in b/tgt-vvp/vvp-s.conf.in index 81c6f4a37..6d45439b8 100644 --- a/tgt-vvp/vvp-s.conf.in +++ b/tgt-vvp/vvp-s.conf.in @@ -3,5 +3,4 @@ functor:synth functor:syn-rules functor:cprop functor:nodangle --t:dll flag:DLL=vvp.tgt diff --git a/tgt-vvp/vvp.conf.in b/tgt-vvp/vvp.conf.in index 2dbe4a66b..c416038ac 100644 --- a/tgt-vvp/vvp.conf.in +++ b/tgt-vvp/vvp.conf.in @@ -1,4 +1,3 @@ functor:cprop functor:nodangle --t:dll flag:DLL=vvp.tgt From 527f5c48493780ff5ae7959058a2b9c4ee92a8be Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 7 Sep 2008 21:54:46 -0700 Subject: [PATCH 29/93] The -V flag gets version information from all parts. When the -V flag is passed to the iverilog command, we can easily print the version information for the driver itself, but it is also valuable to probe all the components that would have been used for a real compile. So the driver executes the preprocessor and the ivl core to have them print version information. The ivl core program also tries to load the target code generator and get version information to print. For this to work, create a new optional entry point "target_query" that takes a query key string as an argument and returns a const string as the result. Use this with the key "version" to get version information out of the target. --- Makefile.in | 25 ++++++- driver/main.c | 157 +++++++++++++++++++++++++++---------------- ivl_target.h | 3 +- ivlpp/Makefile.in | 2 +- ivlpp/main.c | 21 ++++-- main.cc | 24 +++++-- t-dll.cc | 36 ++++++++++ t-dll.h | 4 ++ tgt-null/Makefile.in | 2 +- tgt-null/null.c | 52 +++++++------- tgt-stub/Makefile.in | 2 +- tgt-stub/stub.c | 26 +++++++ tgt-vvp/Makefile.in | 2 +- tgt-vvp/vvp.c | 25 +++++++ 14 files changed, 273 insertions(+), 108 deletions(-) diff --git a/Makefile.in b/Makefile.in index e74325e6d..b5fc3d3d2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -18,6 +18,23 @@ # SHELL = /bin/sh +# Normally, the "make" will build all the files only by dependencies. +# The MODE, however, can control your rebuild intentions. The proper way +# to use the MODE is on the make command like, this this: +# +# make MODE=XXXX all +# +# The possible MODE= values are: +# +# regular +# Build as normal +# +# full +# Do some extra builds. in particular: +# Build version.h again, even if it already exists. +# +MODE=regular + # This version string is only used in the version message printed # by the compiler. It reflects the assigned version number for the # product as a whole. Most components also print the CVS Name: token @@ -52,15 +69,15 @@ MAN = @MAN@ PS2PDF = @PS2PDF@ GIT = @GIT@ -CPPFLAGS = @ident_support@ @DEFS@ -I. -I$(srcdir) @CPPFLAGS@ +CPPFLAGS = @ident_support@ @DEFS@ -I. -I$(srcdir) -DVERSION='"$(VERSION)"' @CPPFLAGS@ CXXFLAGS = -Wall @CXXFLAGS@ PICFLAGS = @PICFLAG@ LDFLAGS = @rdynamic@ @LDFLAGS@ all: dep version.h ivl@EXEEXT@ - for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) $@); done + for dir in $(SUBDIRS); do (cd $$dir ; $(MAKE) VERSION=$(VERSION) $@); done for dir in ivlpp ; \ - do (cd $$dir ; $(MAKE) $@); done + do (cd $$dir ; $(MAKE) VERSION=$(VERSION) $@); done cd driver ; $(MAKE) VERSION=$(VERSION) $@ # In the windows world, the installer will need a dosify program to @@ -186,7 +203,9 @@ iverilog-vpi.pdf: iverilog-vpi.ps # For VERSION_TAG in driver/main.c, first try git-describe, then look for a # version.h file in the source tree (included in snapshots and releases), and # finally use nothing. +ifeq ($(MODE),full) .PHONY: version.h +endif # "true" and "false" in the next few lines are Unix shell command names ifeq ($(GIT),none) GIT_PRESENT = false diff --git a/driver/main.c b/driver/main.c index 932197e82..d0f1c387b 100644 --- a/driver/main.c +++ b/driver/main.c @@ -51,6 +51,7 @@ const char HELP[] = #include #include #include +#include #include #include @@ -259,18 +260,102 @@ static const char*my_tempfile(const char*str, FILE**fout) return pathbuf; } +static int t_version_only(void) +{ + remove(source_path); + + fflush(0); + snprintf(tmp, sizeof tmp, "%s%civlpp -V", pbase, sep); + system(tmp); + + fflush(0); + snprintf(tmp, sizeof tmp, "%s%civl -V -C%s -C%s", pbase, sep, + iconfig_path, iconfig_common_path); + system(tmp); + + if ( ! getenv("IVERILOG_ICONFIG")) { + remove(iconfig_path); + remove(defines_path); + remove(compiled_defines_path); + } + + return 0; +} + +static void build_preprocess_command(int e_flag) +{ + snprintf(tmp, sizeof tmp, "%s%civlpp %s%s -F%s -f%s -p%s ", + pbase,sep, verbose_flag?" -v":"", + e_flag?"":" -L", defines_path, source_path, + compiled_defines_path); +} + +static int t_preprocess_only(void) +{ + int rc; + char*cmd; + unsigned ncmd; + + build_preprocess_command(1); + + ncmd = strlen(tmp); + cmd = malloc(ncmd+1); + strcpy(cmd, tmp); + + if (strcmp(opath,"-") != 0) { + snprintf(tmp, sizeof tmp, " > %s", opath); + cmd = realloc(cmd, ncmd+strlen(tmp)+1); + strcpy(cmd+ncmd, tmp); + ncmd += strlen(tmp); + } + + if (verbose_flag) + printf("preprocess: %s\n", cmd); + + rc = system(cmd); + remove(source_path); + + if ( ! getenv("IVERILOG_ICONFIG")) { + remove(iconfig_path); + remove(defines_path); + remove(compiled_defines_path); + } + + if (rc != 0) { + if (WIFEXITED(rc)) { + fprintf(stderr, "errors preprocessing Verilog program.\n"); + return WEXITSTATUS(rc); + } + + fprintf(stderr, "Command signaled: %s\n", cmd); + free(cmd); + return -1; + } + + return 0; +} + /* * This is the default target type. It looks up the bits that are * needed to run the command from the configuration file (which is * already parsed for us) so we can handle must of the generic cases. */ -static int t_default(char*cmd, unsigned ncmd) +static int t_compile() { unsigned rc; + + /* Start by building the preprocess command line. */ + build_preprocess_command(0); + + size_t ncmd = strlen(tmp); + char*cmd = malloc(ncmd + 1); + strcpy(cmd, tmp); + #ifdef __MINGW32__ unsigned ncmd_start = ncmd; #endif + /* Build the ivl command and pipe it to the preprocessor. */ snprintf(tmp, sizeof tmp, " | %s/ivl", base); rc = strlen(tmp); cmd = realloc(cmd, ncmd+rc+1); @@ -533,8 +618,6 @@ void add_sft_file(const char *module) int main(int argc, char **argv) { - char*cmd; - unsigned ncmd; int e_flag = 0; int version_flag = 0; int opt, idx, rc; @@ -748,9 +831,6 @@ int main(int argc, char **argv) printf("Icarus Verilog version " VERSION " (" VERSION_TAG ")\n\n"); printf("Copyright 1998-2008 Stephen Williams\n"); puts(NOTICE); - - if (version_flag) - return 0; } /* Make a common conf file path to reflect the target. */ @@ -833,61 +913,11 @@ int main(int argc, char **argv) fclose(defines_file); defines_file = 0; - if (source_count == 0) { + if (source_count == 0 && !version_flag) { fprintf(stderr, "%s: no source files.\n\n%s\n", argv[0], HELP); return 1; } - - /* Start building the preprocess command line. */ - - sprintf(tmp, "%s%civlpp %s%s -F%s -f%s -p%s ", pbase,sep, - verbose_flag?" -v":"", - e_flag?"":" -L", defines_path, source_path, - compiled_defines_path); - - ncmd = strlen(tmp); - cmd = malloc(ncmd + 1); - strcpy(cmd, tmp); - - /* If the -E flag was given on the command line, then all we - do is run the preprocessor and put the output where the - user wants it. */ - if (e_flag) { - int rc; - if (strcmp(opath,"-") != 0) { - sprintf(tmp, " > %s", opath); - cmd = realloc(cmd, ncmd+strlen(tmp)+1); - strcpy(cmd+ncmd, tmp); - ncmd += strlen(tmp); - } - - if (verbose_flag) - printf("preprocess: %s\n", cmd); - - rc = system(cmd); - remove(source_path); - fclose(iconfig_file); - if ( ! getenv("IVERILOG_ICONFIG")) { - remove(iconfig_path); - remove(defines_path); - remove(compiled_defines_path); - } - - if (rc != 0) { - if (WIFEXITED(rc)) { - fprintf(stderr, "errors preprocessing Verilog program.\n"); - return WEXITSTATUS(rc); - } - - fprintf(stderr, "Command signaled: %s\n", cmd); - free(cmd); - return -1; - } - - return 0; - } - fprintf(iconfig_file, "iwidth:%u\n", integer_width); /* Write the preprocessor command needed to preprocess a @@ -899,5 +929,16 @@ int main(int argc, char **argv) /* Done writing to the iconfig file. Close it now. */ fclose(iconfig_file); - return t_default(cmd, ncmd); + /* If we're only here for th verion output, then we're done. */ + if (version_flag) + return t_version_only(); + + /* If the -E flag was given on the command line, then all we + do is run the preprocessor and put the output where the + user wants it. */ + if (e_flag) + return t_preprocess_only(); + + /* Otherwise, this is a full compile. */ + return t_compile(); } diff --git a/ivl_target.h b/ivl_target.h index f198fe55d..58c27e424 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -1927,7 +1927,7 @@ extern unsigned ivl_switch_lineno(ivl_switch_t net); #endif extern DLLEXPORT int target_design(ivl_design_t des); - +extern DLLEXPORT const char* target_query(const char*key); /* target_design @@ -1945,6 +1945,7 @@ extern DLLEXPORT int target_design(ivl_design_t des); ivl core. This function is how the target module is invoked. */ typedef int (*target_design_f)(ivl_design_t des); +typedef const char* (*target_query_f) (const char*key); _END_DECL diff --git a/ivlpp/Makefile.in b/ivlpp/Makefile.in index b66ed207a..2a3e0d22f 100644 --- a/ivlpp/Makefile.in +++ b/ivlpp/Makefile.in @@ -40,7 +40,7 @@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ -CPPFLAGS = @ident_support@ -I. -I.. -I$(srcdir)/.. -I$(srcdir) @CPPFLAGS@ @DEFS@ +CPPFLAGS = @ident_support@ -I. -I.. -I$(srcdir)/.. -I$(srcdir) -DVERSION='"$(VERSION)"' @CPPFLAGS@ @DEFS@ CFLAGS = -Wall @CFLAGS@ LDFLAGS = @LDFLAGS@ diff --git a/ivlpp/main.c b/ivlpp/main.c index 7c91ed853..5aa3097ed 100644 --- a/ivlpp/main.c +++ b/ivlpp/main.c @@ -17,7 +17,8 @@ const char COPYRIGHT[] = * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -# include "config.h" +# include "config.h" +# include "version.h" const char NOTICE[] = " This program is free software; you can redistribute it and/or modify\n" @@ -35,8 +36,6 @@ const char NOTICE[] = " Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA\n" ; -const char VERSION[] = "$Name: $ $State: Exp $"; - # include # include #ifdef HAVE_MALLOC_H @@ -229,7 +228,7 @@ int main(int argc, char*argv[]) include_dir[0] = 0; /* 0 is reserved for the current files path. */ include_dir[1] = strdup("."); - while ((opt=getopt(argc, argv, "F:f:K:Lo:p:P:v")) != EOF) switch (opt) { + while ((opt=getopt(argc, argv, "F:f:K:Lo:p:P:vV")) != EOF) switch (opt) { case 'F': flist_read_flags(optarg); @@ -284,12 +283,19 @@ int main(int argc, char*argv[]) } case 'v': - fprintf(stderr, "Icarus Verilog Preprocessor version %s\n", - VERSION); + fprintf(stderr, "Icarus Verilog Preprocessor version " + VERSION " (" VERSION_TAG ")\n\n"); fprintf(stderr, "%s\n", COPYRIGHT); fputs(NOTICE, stderr); break; + case 'V': + fprintf(stdout, "Icarus Verilog Preprocessor version " + VERSION " (" VERSION_TAG ")\n\n"); + fprintf(stdout, "%s\n", COPYRIGHT); + fputs(NOTICE, stdout); + return 0; + default: flag_errors += 1; break; @@ -304,7 +310,8 @@ int main(int argc, char*argv[]) " -o - Send the output to \n" " -p - Write precompiled defines to \n" " -P - Read precompiled defines from \n" - " -v - Print version information\n", + " -v - Verbose\n" + " -V - Print version information and quit\n", argv[0]); return flag_errors; } diff --git a/main.cc b/main.cc index 6cab41113..99bfa4a2c 100644 --- a/main.cc +++ b/main.cc @@ -20,6 +20,7 @@ const char COPYRIGHT[] = */ # include "config.h" +# include "version.h" const char NOTICE[] = " This program is free software; you can redistribute it and/or modify\n" @@ -76,8 +77,6 @@ extern "C" const char*optarg; /* Count errors detected in flag processing. */ unsigned flag_errors = 0; -const char VERSION[] = "$Name: $"; - const char*basedir = "."; /* @@ -532,6 +531,7 @@ int main(int argc, char*argv[]) { bool help_flag = false; bool times_flag = false; + bool version_flag = false; const char* net_path = 0; const char* pf_path = 0; @@ -575,10 +575,8 @@ int main(int argc, char*argv[]) # endif break; case 'V': - cout << "Icarus Verilog version " << VERSION << endl; - cout << COPYRIGHT << endl; - cout << endl << NOTICE << endl; - return 0; + version_flag = true; + break; default: flag_errors += 1; break; @@ -587,8 +585,20 @@ int main(int argc, char*argv[]) if (flag_errors) return flag_errors; + if (version_flag) { + cout << "\n\nIcarus Verilog Parser/Elaborator version " + << VERSION << " (" << VERSION_TAG << ")" << endl; + cout << COPYRIGHT << endl; + cout << endl << NOTICE << endl; + + dll_target_obj.test_version(flags["DLL"]); + + return 0; + } + if (help_flag) { - cout << "Icarus Verilog version " << VERSION << endl << + cout << "Icarus Verilog Parser/Elaborator version " + << VERSION << " (" << VERSION_TAG << ")" << endl << "usage: ivl \n" "options:\n" "\t-C Config file from driver.\n" diff --git a/t-dll.cc b/t-dll.cc index e171babdc..d09536f01 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -2578,3 +2578,39 @@ bool dll_target::signal_paths(const NetNet*net) return true; } + + +void dll_target::test_version(const char*target_name) +{ + dll_ = ivl_dlopen(target_name); + + if ((dll_ == 0) && (target_name[0] != '/')) { + size_t len = strlen(basedir) + 1 + strlen(target_name) + 1; + char*tmp = new char[len]; + sprintf(tmp, "%s/%s", basedir, target_name); + dll_ = ivl_dlopen(tmp); + delete[]tmp; + } + + if (dll_ == 0) { + cout << "\n\nUnable to load " << target_name + << " for version details." << endl; + return; + } + + target_query_f target_query = (target_query_f)ivl_dlsym(dll_, LU "target_query" TU); + if (target_query == 0) { + cerr << "Target " << target_name + << " has no version hooks." << endl; + return; + } + + const char*version_string = (*target_query) ("version"); + if (version_string == 0) { + cerr << "Target " << target_name + << " has no version string" << endl; + return; + } + + cout << target_name << ": " << version_string << endl; +} diff --git a/t-dll.h b/t-dll.h index d13d43ce8..02a6418c8 100644 --- a/t-dll.h +++ b/t-dll.h @@ -63,6 +63,10 @@ struct ivl_design_s { */ struct dll_target : public target_t, public expr_scan_t { + // This is a special function for loading and testing the + // version of a loadable target code generator. + void test_version(const char*target_name); + bool start_design(const Design*); int end_design(const Design*); diff --git a/tgt-null/Makefile.in b/tgt-null/Makefile.in index 426d35230..845b2f0e1 100644 --- a/tgt-null/Makefile.in +++ b/tgt-null/Makefile.in @@ -35,7 +35,7 @@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ -CPPFLAGS = @ident_support@ -I.. -I$(srcdir)/.. -I$(srcdir) @CPPFLAGS@ @DEFS@ @PICFLAG@ +CPPFLAGS = @ident_support@ -I.. -I$(srcdir)/.. -I$(srcdir) -DVERSION='"$(VERSION)"' @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = -Wall @CFLAGS@ LDFLAGS = @LDFLAGS@ diff --git a/tgt-null/null.c b/tgt-null/null.c index 97e245b89..516c3cd37 100644 --- a/tgt-null/null.c +++ b/tgt-null/null.c @@ -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: null.c,v 1.7 2002/08/12 01:35:03 steve Exp $" -#endif # include "config.h" @@ -28,35 +25,34 @@ # include "ivl_target.h" +static const char*version_string = +"Icarus Verilog NULL Code Generator " VERSION "\n" +" This program is free software; you can redistribute it and/or modify\n" +" it under the terms of the GNU General Public License as published by\n" +" the Free Software Foundation; either version 2 of the License, or\n" +" (at your option) any later version.\n" +"\n" +" This program is distributed in the hope that it will be useful,\n" +" but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +" GNU General Public License for more details.\n" +"\n" +" You should have received a copy of the GNU General Public License\n" +" along with this program; if not, write to the Free Software\n" +" Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA\n" +; + int target_design(ivl_design_t des) { return 0; } -/* - * $Log: null.c,v $ - * Revision 1.7 2002/08/12 01:35:03 steve - * conditional ident string using autoconfig. - * - * Revision 1.6 2001/09/30 16:45:10 steve - * Fix some Cygwin DLL handling. (Venkat Iyer) - * - * Revision 1.5 2001/07/25 03:10:50 steve - * Create a config.h.in file to hold all the config - * junk, and support gcc 3.0. (Stephan Boettcher) - * - * Revision 1.4 2001/05/22 02:14:47 steve - * Update the mingw build to not require cygwin files. - * - * Revision 1.3 2001/05/20 15:09:40 steve - * Mingw32 support (Venkat Iyer) - * - * Revision 1.2 2001/02/07 22:21:59 steve - * ivl_target header search path fixes. - * - * Revision 1.1 2000/12/02 04:50:32 steve - * Make the null target into a loadable target. - * - */ +const char* target_query(const char*key) +{ + if (strcmp(key,"version") == 0) + return version_string; + + return 0; +} diff --git a/tgt-stub/Makefile.in b/tgt-stub/Makefile.in index 20d0136f9..fbf4702b3 100644 --- a/tgt-stub/Makefile.in +++ b/tgt-stub/Makefile.in @@ -35,7 +35,7 @@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ -CPPFLAGS = @ident_support@ -I.. -I$(srcdir)/.. @CPPFLAGS@ @DEFS@ @PICFLAG@ +CPPFLAGS = @ident_support@ -I.. -I$(srcdir)/.. -DVERSION='"$(VERSION)"' @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = -Wall @CFLAGS@ LDFLAGS = @LDFLAGS@ diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index fb170fb00..13da6f4d2 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -28,8 +28,26 @@ # include "priv.h" # include # include +# include # include +static const char*version_string = +"Icarus Verilog Stub Target " VERSION "\n" +" This program is free software; you can redistribute it and/or modify\n" +" it under the terms of the GNU General Public License as published by\n" +" the Free Software Foundation; either version 2 of the License, or\n" +" (at your option) any later version.\n" +"\n" +" This program is distributed in the hope that it will be useful,\n" +" but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +" GNU General Public License for more details.\n" +"\n" +" You should have received a copy of the GNU General Public License\n" +" along with this program; if not, write to the Free Software\n" +" Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA\n" +; + FILE*out; int stub_errors = 0; @@ -1608,3 +1626,11 @@ int target_design(ivl_design_t des) return stub_errors; } + +const char* target_query(const char*key) +{ + if (strcmp(key,"version") == 0) + return version_string; + + return 0; +} diff --git a/tgt-vvp/Makefile.in b/tgt-vvp/Makefile.in index f3e8b9b0d..b71c1310a 100644 --- a/tgt-vvp/Makefile.in +++ b/tgt-vvp/Makefile.in @@ -38,7 +38,7 @@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ -CPPFLAGS = @ident_support@ -I. -I$(srcdir)/.. @CPPFLAGS@ @DEFS@ @PICFLAG@ +CPPFLAGS = @ident_support@ -I. -I$(srcdir)/.. -DVERSION='"$(VERSION)"' @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = -Wall @CFLAGS@ LDFLAGS = @LDFLAGS@ diff --git a/tgt-vvp/vvp.c b/tgt-vvp/vvp.c index e1cb632f3..72f16b200 100644 --- a/tgt-vvp/vvp.c +++ b/tgt-vvp/vvp.c @@ -26,6 +26,23 @@ # include # include +static const char*version_string = +"Icarus Verilog VVP Code Generator " VERSION "\n" +" This program is free software; you can redistribute it and/or modify\n" +" it under the terms of the GNU General Public License as published by\n" +" the Free Software Foundation; either version 2 of the License, or\n" +" (at your option) any later version.\n" +"\n" +" This program is distributed in the hope that it will be useful,\n" +" but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +" GNU General Public License for more details.\n" +"\n" +" You should have received a copy of the GNU General Public License\n" +" along with this program; if not, write to the Free Software\n" +" Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA\n" +; + FILE*vvp_out = 0; int vvp_errors = 0; @@ -119,3 +136,11 @@ int target_design(ivl_design_t des) return rc + vvp_errors; } + +const char* target_query(const char*key) +{ + if (strcmp(key,"version") == 0) + return version_string; + + return 0; +} From eb9d037bf027bae359ae956608547c209b2ff112 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 8 Sep 2008 19:13:49 -0700 Subject: [PATCH 30/93] Remove elaborate_net from all elaborations. Use elaborate_expr and synthesize() methods in place of the elaborate_net methods, so that elaboration is more consistent. --- elaborate.cc | 58 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index 43b3c860f..14cdd478c 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -648,9 +648,18 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const des->errors += 1; return; } - NetNet*sig = (idx == 0) - ? lval_sig - : ex->elaborate_net(des, scope, 0, 0, 0, 0); + NetNet*sig = 0; + if (idx == 0) { + sig = lval_sig; + + } else { + unsigned use_width = count * instance_width; + NetExpr*tmp = elab_and_eval(des, scope, ex, + use_width, use_width); + sig = tmp->synthesize(des, scope); + delete tmp; + } + if (sig == 0) continue; @@ -1067,9 +1076,16 @@ v NOTE that this also handles the case that the port is actually empty on the inside. We assume in that case that the port is input. */ - sig = pins[idx]->elaborate_net(des, scope, - desired_vector_width, - 0, 0, 0); + NetExpr*tmp_expr = elab_and_eval(des, scope, pins[idx], + desired_vector_width, + desired_vector_width); + if (tmp_expr == 0) { + cerr << pins[idx]->get_fileline() + << ": internal error: Port expression " + << "too complicated for elaboration." << endl; + continue; + } + sig = tmp_expr->synthesize(des, scope); if (sig == 0) { cerr << pins[idx]->get_fileline() << ": internal error: Port expression " @@ -1077,6 +1093,9 @@ v NOTE that this also handles the case that the continue; } + delete tmp_expr; + sig->set_line(*this); + if (need_bufz_for_input_port(prts)) { NetBUFZ*tmp = new NetBUFZ(scope, scope->local_symbol(), sig->vector_width()); @@ -1487,12 +1506,17 @@ void PGModule::elaborate_udp_(Design*des, PUdp*udp, NetScope*scope) const if (pins[idx] == 0) continue; - NetNet*sig = pins[idx]->elaborate_net(des, scope, 1, 0, 0, 0); - if (sig == 0) { + NetExpr*expr_tmp = elab_and_eval(des, scope, pins[idx], 1, 1); + if (expr_tmp == 0) { cerr << "internal error: Expression too complicated " "for elaboration:" << pins[idx] << endl; continue; } + NetNet*sig = expr_tmp->synthesize(des, scope); + ivl_assert(*this, sig); + sig->set_line(*this); + + delete expr_tmp; connect(sig->pin(0), net->pin(idx)); } @@ -2668,17 +2692,29 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope, bool save_flag = error_implicit; error_implicit = true; - NetNet*expr = expr_[idx]->expr()->elaborate_net(des, scope, - 0, 0, 0, 0); - error_implicit = save_flag; + NetExpr*tmp = elab_and_eval(des, scope, expr_[idx]->expr(), 0); + if (tmp == 0) { + expr_[idx]->dump(cerr); + cerr << endl; + des->errors += 1; + error_implicit = save_flag; + continue; + } + + NetNet*expr = tmp->synthesize(des, scope); + expr->set_line(*this); if (expr == 0) { expr_[idx]->dump(cerr); cerr << endl; des->errors += 1; + error_implicit = save_flag; continue; } assert(expr); + delete tmp; + + error_implicit = save_flag; unsigned pins = (expr_[idx]->type() == PEEvent::ANYEDGE) ? expr->pin_count() : 1; From 05f129211e9ada4e81fae45dfa5503695ba4baa1 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 8 Sep 2008 21:26:26 -0700 Subject: [PATCH 31/93] Remove the elaborate_net methods. These methods are no longer in use, their functionality taked over by a compination of elab_and_eval and NetExpr::synthesize methods. --- PExpr.h | 195 +--- elab_net.cc | 3118 --------------------------------------------------- 2 files changed, 1 insertion(+), 3312 deletions(-) diff --git a/PExpr.h b/PExpr.h index 3ef8f331f..cbc17b0fb 100644 --- a/PExpr.h +++ b/PExpr.h @@ -36,9 +36,6 @@ class NetScope; * The PExpr class hierarchy supports the description of * expressions. The parser can generate expression objects from the * source, possibly reducing things that it knows how to reduce. - * - * The elaborate_net method is used by structural elaboration to build - * up a netlist interpretation of the expression. */ class PExpr : public LineInfo { @@ -98,17 +95,6 @@ class PExpr : public LineInfo { // evaluation of parameters. virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; - // This method elaborate the expression as gates, for use in a - // continuous assign or other wholly structural context. - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0 =Link::STRONG, - Link::strength_t drive1 =Link::STRONG) - const; - // This method elaborates the expression as gates, but // restricted for use as l-values of continuous assignments. virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const; @@ -163,13 +149,6 @@ class PEConcat : public PExpr { virtual bool elaborate_sig(Design*des, NetScope*scope) const; virtual NetNet* elaborate_lnet(Design*des, NetScope*scope) const; virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const; - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; virtual NetExpr*elaborate_expr(Design*des, NetScope*, int expr_width, bool sys_task_arg) const; virtual NetEConcat*elaborate_pexpr(Design*des, NetScope*) const; @@ -236,14 +215,6 @@ class PEFNumber : public PExpr { int expr_width, bool sys_task_arg) const; virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - virtual void dump(ostream&) const; private: @@ -278,15 +249,6 @@ class PEIdent : public PExpr { NetScope*scope, bool is_force) const; - // Structural r-values are OK. - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - virtual NetExpr*elaborate_expr(Design*des, NetScope*, int expr_width, bool sys_task_arg) const; virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; @@ -366,38 +328,6 @@ class PEIdent : public PExpr { NetESignal*net, NetScope*found) const; - public: - - NetNet* elaborate_net_array_(Design*des, NetScope*scope, - NetNet*sig, unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - - NetNet* elaborate_net_net_(Design*des, NetScope*scope, - NetNet*sig, unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - NetNet* elaborate_net_net_idx_up_(Design*des, NetScope*scope, - NetNet*sig, unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - NetNet* elaborate_net_bitmux_(Design*des, NetScope*scope, - NetNet*sig, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - private: NetNet* elaborate_lnet_common_(Design*des, NetScope*scope, bool bidirectional_flag) const; @@ -406,8 +336,6 @@ class PEIdent : public PExpr { bool eval_part_select_(Design*des, NetScope*scope, NetNet*sig, long&midx, long&lidx) const; - NetNet*process_select_(Design*des, NetScope*scope, NetNet*sig) const; - }; class PENumber : public PExpr { @@ -423,13 +351,6 @@ class PENumber : public PExpr { unsigned min, unsigned lval, bool&unsized_flag) const; - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; virtual NetEConst*elaborate_expr(Design*des, NetScope*, int expr_width, bool) const; virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; @@ -466,13 +387,6 @@ class PEString : public PExpr { unsigned min, unsigned lval, bool&unsized_flag) const; - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; virtual NetEConst*elaborate_expr(Design*des, NetScope*, int expr_width, bool) const; virtual NetEConst*elaborate_pexpr(Design*des, NetScope*sc) const; @@ -498,13 +412,6 @@ class PEUnary : public PExpr { virtual bool elaborate_sig(Design*des, NetScope*scope) const; - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; virtual NetExpr*elaborate_expr(Design*des, NetScope*, int expr_width, bool sys_task_arg) const; virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; @@ -512,32 +419,6 @@ class PEUnary : public PExpr { virtual bool is_constant(Module*) const; - private: - NetNet* elab_net_uminus_const_logic_(Design*des, NetScope*scope, - NetEConst*expr, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - NetNet* elab_net_uminus_const_real_(Design*des, NetScope*scope, - NetECReal*expr, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - NetNet* elab_net_unary_real_(Design*des, NetScope*scope, - NetExpr*expr, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - private: char op_; PExpr*expr_; @@ -559,13 +440,6 @@ class PEBinary : public PExpr { virtual bool elaborate_sig(Design*des, NetScope*scope) const; - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; virtual NetExpr*elaborate_expr(Design*des, NetScope*, int expr_width, bool sys_task_arg) const; virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; @@ -585,52 +459,6 @@ class PEBinary : public PExpr { static void suppress_operand_sign_if_needed_(NetExpr*lp, NetExpr*rp); - private: - NetNet* elaborate_net_add_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; - NetNet* elaborate_net_bit_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; - NetNet* elaborate_net_cmp_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; - NetNet* elaborate_net_div_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; - NetNet* elaborate_net_mod_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; - NetNet* elaborate_net_log_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; - NetNet* elaborate_net_mul_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; - NetNet* elaborate_net_pow_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; - NetNet* elaborate_net_shift_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const; }; /* @@ -680,13 +508,6 @@ class PETernary : public PExpr { virtual bool elaborate_sig(Design*des, NetScope*scope) const; - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; virtual NetExpr*elaborate_expr(Design*des, NetScope*, int expr_width, bool sys_task_arg) const; virtual NetETernary*elaborate_pexpr(Design*des, NetScope*sc) const; @@ -720,14 +541,7 @@ class PECallFunction : public PExpr { virtual void dump(ostream &) const; - virtual NetNet* elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; - virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, + virtual NetExpr*elaborate_expr(Design*des, NetScope*scope, int expr_wid, bool sys_task_arg) const; virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; @@ -743,13 +557,6 @@ class PECallFunction : public PExpr { NetExpr* elaborate_sfunc_(Design*des, NetScope*scope, int expr_wid) const; NetExpr* elaborate_access_func_(Design*des, NetScope*scope, int expr_wid) const; - NetNet* elaborate_net_sfunc_(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const; unsigned test_width_sfunc_(Design*des, NetScope*scope, unsigned min, unsigned lval, bool&unsized_flag) const; diff --git a/elab_net.cc b/elab_net.cc index a94446fe8..daa45e64f 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -29,2310 +29,6 @@ # include # include "ivl_assert.h" -/* - * This is a state flag that determines whether an elaborate_net must - * report an error when it encounters an unsized number. Normally, it - * is fine to make an unsized number as small as it can be, but there - * are a few cases where the size must be fully self-determined. For - * example, within a {...} (concatenation) operator. - */ -static bool must_be_self_determined_flag = false; - -NetNet* PExpr::elaborate_net(Design*des, NetScope*scope, unsigned, - const NetExpr*, - const NetExpr*, - const NetExpr*, - Link::strength_t, - Link::strength_t) const -{ - cerr << get_fileline() << ": error: Unable to elaborate `" - << *this << "' as gates." << endl; - return 0; -} - -/* - * Elaborating binary operations generally involves elaborating the - * left and right expressions, then making an output wire and - * connecting the lot together with the right kind of gate. - */ -NetNet* PEBinary::elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - switch (op_) { - case '*': - return elaborate_net_mul_(des, scope, width, rise, fall, decay); - case '%': - return elaborate_net_mod_(des, scope, width, rise, fall, decay); - case '/': - return elaborate_net_div_(des, scope, width, rise, fall, decay); - case 'p': // ** - return elaborate_net_pow_(des, scope, width, rise, fall, decay); - case '+': - case '-': - return elaborate_net_add_(des, scope, width, rise, fall, decay); - case '|': // Bitwise OR - case '&': - case '^': - case 'A': // Bitwise NAND (~&) - case 'O': // Bitwise NOR (~|) - case 'X': // Exclusive NOR - return elaborate_net_bit_(des, scope, width, rise, fall, decay); - case 'E': // === (case equals) - case 'e': // == - case 'N': // !== (case not-equals) - case 'n': // != - case '<': - case '>': - case 'L': // <= - case 'G': // >= - return elaborate_net_cmp_(des, scope, width, rise, fall, decay); - case 'a': // && (logical and) - case 'o': // || (logical or) - return elaborate_net_log_(des, scope, width, rise, fall, decay); - case 'l': // << - case 'r': // >> - case 'R': // >>> - return elaborate_net_shift_(des, scope, width, rise, fall, decay); - } - - /* This is an undefined operator, but we may as well check the - arguments since we are here. */ - NetNet*lsig = left_->elaborate_net(des, scope, width, 0, 0, 0), - *rsig = right_->elaborate_net(des, scope, width, 0, 0, 0); - if (lsig == 0) { - cerr << get_fileline() << ": error: Cannot elaborate "; - left_->dump(cerr); - cerr << endl; - } - if (rsig == 0) { - cerr << get_fileline() << ": error: Cannot elaborate "; - right_->dump(cerr); - cerr << endl; - } - - /* We can only get here with an undefined operator. */ - cerr << get_fileline() << ": internal error: unsupported" - " combinational operator (" << op_ << ")." << endl; - des->errors += 1; - - return 0; -} - -/* - * Elaborate the structural +/- as an AddSub object. Connect DataA and - * DataB to the parameters, and connect the output signal to the - * Result. In this context, the device is a combinational adder with - * fixed direction, so leave Add_Sub unconnected and set the - * LPM_Direction property. - */ -NetNet* PEBinary::elaborate_net_add_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const -{ - NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0), - *rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0); - - if (lsig == 0 || rsig == 0) return 0; - - NetNet*osig; - - unsigned width = lsig->vector_width(); - if (rsig->vector_width() > lsig->vector_width()) - width = rsig->vector_width(); - - - /* The owidth is the output width of the lpm_add_sub - device. If the desired width is greater than the width of - the operands, then widen the adder and let code below pad - the operands. */ - unsigned owidth = width; - switch (op_) { - case '+': - if (lwidth > owidth) { - owidth = lwidth; - width = lwidth; - } - break; - case '-': - if (lwidth > owidth) { - owidth = lwidth; - width = lwidth; - } - break; - default: - assert(0); - } - - bool expr_signed = lsig->get_signed() && rsig->get_signed(); - - // Pad out the operands, if necessary, the match the width of - // the adder device. - if (lsig->vector_width() < width) { - if (expr_signed) - lsig = pad_to_width_signed(des, lsig, width); - else - lsig = pad_to_width(des, lsig, width); - } - - if (rsig->vector_width() < width) { - if (expr_signed) - rsig = pad_to_width_signed(des, rsig, width); - else - rsig = pad_to_width(des, rsig, width); - } - - // Check that the argument types match. - if (lsig->data_type() != rsig->data_type()) { - cerr << get_fileline() << ": error: Arguments of add/sub " - << "have different data types." << endl; - cerr << get_fileline() << ": : Left argument is " - << lsig->data_type() << ", right argument is " - << rsig->data_type() << "." << endl; - des->errors += 1; - return 0; - } - - // Make the adder as wide as the widest operand - osig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, owidth); - osig->data_type(lsig->data_type()); - osig->set_signed(expr_signed); - osig->local_flag(true); - osig->set_line(*this); - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate NetAddSub " - << "width=" << width << " lwidth=" << lwidth - << endl; - } - NetAddSub*adder = new NetAddSub(scope, scope->local_symbol(), width); - - // Connect the adder to the various parts. - connect(lsig->pin(0), adder->pin_DataA()); - connect(rsig->pin(0), adder->pin_DataB()); - connect(osig->pin(0), adder->pin_Result()); -#ifdef XXXX - if (owidth > width) - connect(osig->pin(width), adder->pin_Cout()); -#endif - NetNode*gate = adder; - gate->set_line(*this); - gate->rise_time(rise); - gate->fall_time(fall); - gate->decay_time(decay); - des->add_node(gate); - - gate->attribute(perm_string::literal("LPM_Direction"), - verinum(op_ == '+' ? "ADD" : "SUB")); - - return osig; -} - -/* - * Elaborate various bitwise logic operators. These are all similar in - * that they take operants of equal width, and each bit does not - * affect any other bits. Also common about all this is how bit widths - * of the operands are handled, when they do not match. - */ -NetNet* PEBinary::elaborate_net_bit_(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const -{ - NetNet*lsig = left_->elaborate_net(des, scope, width, 0, 0, 0), - *rsig = right_->elaborate_net(des, scope, width, 0, 0, 0); - - if (lsig == 0 || rsig == 0) return 0; - - if (lsig->vector_width() < rsig->vector_width()) - lsig = pad_to_width(des, lsig, rsig->vector_width()); - if (rsig->vector_width() < lsig->vector_width()) - rsig = pad_to_width(des, rsig, lsig->vector_width()); - - if (lsig->data_type() != rsig->data_type()) { - cerr << get_fileline() << ": error: Types of " - << "operands of " << op_ << " do not match: " - << lsig->data_type() << " vs. " << rsig->data_type() - << endl; - des->errors += 1; - return 0; - } - - /* The types match here and real is not supported. */ - if (lsig->data_type() == IVL_VT_REAL) { - cerr << get_fileline() << ": error: " << human_readable_op(op_) - << " operator may not have REAL operands." << endl; - des->errors += 1; - return 0; - } - - if (lsig->vector_width() != rsig->vector_width()) { - cerr << get_fileline() << ": internal error: lsig width (" - << lsig->vector_width() << ") != rsig pin width (" - << rsig->vector_width() << ")." << endl; - des->errors += 1; - return 0; - } - - assert(lsig->vector_width() == rsig->vector_width()); - - NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, - lsig->vector_width()); - osig->local_flag(true); - osig->set_line(*this); - osig->data_type( lsig->data_type() ); - - NetLogic::TYPE gtype=NetLogic::AND; - switch (op_) { - case '^': gtype = NetLogic::XOR; break; // XOR - case 'X': gtype = NetLogic::XNOR; break; // XNOR - case '&': gtype = NetLogic::AND; break; // AND - case 'A': gtype = NetLogic::NAND; break; // NAND (~&) - case '|': gtype = NetLogic::OR; break; // Bitwise OR - case 'O': gtype = NetLogic::NOR; break; // Bitwise NOR - default: assert(0); - } - - NetLogic*gate = new NetLogic(scope, scope->local_symbol(), - 3, gtype, osig->vector_width()); - 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)); - gate->rise_time(rise); - gate->fall_time(fall); - gate->decay_time(decay); - des->add_node(gate); - - return osig; -} - -/* - * This function attempts to handle the special case of == or != - * compare to a constant value. The caller has determined already that - * one of the operands is a NetEConst, and has already elaborated the - * other. - */ -static NetNet* compare_eq_constant(Design*des, NetScope*scope, - NetNet*lsig, NetEConst*rexp, - char op_code, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) -{ - if (op_code != 'e' && op_code != 'n') - return 0; - - verinum val = rexp->value(); - - /* Abandon special case if there are x or z bits in the - constant. We can't get the right behavior out of - OR/NOR in this case. */ - if (! val.is_defined()) - return 0; - - if (val.len() < lsig->vector_width()) - val = verinum(val, lsig->vector_width()); - - /* Look for the very special case that we know the compare - results a priori due to different high bits, that are - constant pad in the signal. */ - if (val.len() > lsig->vector_width()) { - unsigned idx = lsig->vector_width(); - verinum::V lpad = verinum::V0; - - while (idx < val.len()) { - if (val.get(idx) != lpad) { - verinum oval (op_code == 'e' - ? verinum::V0 - : verinum::V1, - 1); - NetEConst*ogate = new NetEConst(oval); - NetNet*osig = ogate->synthesize(des, scope); - osig->data_type(lsig->data_type()); - osig->set_line(*lsig); - osig->rise_time(rise); - osig->fall_time(fall); - osig->decay_time(decay); - delete ogate; - - if (debug_elaborate) - cerr << lsig->get_fileline() << ": debug: " - << "Equality replaced with " - << oval << " due to high pad mismatch" - << endl; - - return osig; - } - - idx +=1; - } - } - - unsigned zeros = 0; - unsigned ones = 0; - for (unsigned idx = 0 ; idx < lsig->vector_width() ; idx += 1) { - if (val.get(idx) == verinum::V0) - zeros += 1; - if (val.get(idx) == verinum::V1) - ones += 1; - } - - /* Handle the special case that the gate is a compare that can - be replaces with a reduction AND or NOR. */ - - if (ones == 0 || zeros == 0) { - NetUReduce::TYPE type; - - if (zeros > 0) { - type = op_code == 'e'? NetUReduce::NOR : NetUReduce::OR; - - if (debug_elaborate) - cerr << lsig->get_fileline() << ": debug: " - << "Replace net==" << val << " equality with " - << zeros << "-input reduction [N]OR gate." << endl; - - } else { - type = op_code == 'e'? NetUReduce::AND : NetUReduce::NAND; - - if (debug_elaborate) - cerr << lsig->get_fileline() << ": debug: " - << "Replace net==" << val << " equality with " - << ones << "-input reduction AND gate." << endl; - } - - NetUReduce*red = new NetUReduce(scope, scope->local_symbol(), - type, zeros+ones); - des->add_node(red); - red->set_line(*lsig); - red->rise_time(rise); - red->fall_time(fall); - red->decay_time(decay); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, 0, 0); - tmp->data_type(lsig->data_type()); - tmp->local_flag(true); - tmp->set_line(*lsig); - - connect(red->pin(1), lsig->pin(0)); - connect(red->pin(0), tmp->pin(0)); - return tmp; - } - - if (debug_elaborate) - cerr << lsig->get_fileline() << ": debug: " - << "Give up trying to replace net==" << val - << " equality with " - << ones << "-input AND and " - << zeros << "-input NOR gates." << endl; - - return 0; -} - -/* - * Elaborate the various binary comparison operators. The comparison - * operators return a single bit result, no matter what, so the left - * and right values can have their own size. The only restriction is - * that they have the same size. - */ -NetNet* PEBinary::elaborate_net_cmp_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const -{ - /* Elaborate the operands of the compare first as expressions - (so that the eval_tree method can reduce constant - expressions, including parameters) then turn those results - into synthesized nets. */ - NetExpr*lexp = elab_and_eval(des, scope, left_, -1), - *rexp = elab_and_eval(des, scope, right_, -1); - - if (lexp == 0 || rexp == 0) return 0; - - bool real_arg = true; - if (lexp->expr_type() != IVL_VT_REAL && - rexp->expr_type() != IVL_VT_REAL) { - /* Choose the operand width to be the width of the widest - self-determined operand. */ - unsigned operand_width = lexp->expr_width(); - if (rexp->expr_width() > operand_width) - operand_width = rexp->expr_width(); - - lexp->set_width(operand_width); - lexp = pad_to_width(lexp, operand_width); - rexp->set_width(operand_width); - rexp = pad_to_width(rexp, operand_width); - - real_arg = false; - } - - NetNet*lsig = 0; - NetNet*rsig = 0; - - /* Handle the special case that the right or left - sub-expression is a constant value. The compare_eq_constant - function will return an elaborated result if it can make - use of the situation, or 0 if it cannot. */ - if (NetEConst*tmp = dynamic_cast(rexp)) { - - lsig = lexp->synthesize(des, scope); - if (lsig == 0) return 0; - delete lexp; - lexp = 0; - - if (real_arg) { - verireal vrl(tmp->value().as_double()); - NetECReal rlval(vrl); - rsig = rlval.synthesize(des, scope); - delete rexp; - rexp = 0; - } else { - NetNet*osig = compare_eq_constant(des, scope, - lsig, tmp, op_, - rise, fall, decay); - if (osig != 0) { - delete rexp; - return osig; - } - } - } - - if (NetEConst*tmp = dynamic_cast(lexp)) { - - rsig = rexp->synthesize(des, scope); - if (rsig == 0) return 0; - delete rexp; - rexp = 0; - - if (real_arg) { - verireal vrl(tmp->value().as_double()); - NetECReal rlval(vrl); - lsig = rlval.synthesize(des, scope); - delete lexp; - lexp = 0; - } else { - NetNet*osig = compare_eq_constant(des, scope, - rsig, tmp, op_, - rise, fall, decay); - if (osig != 0) { - delete lexp; - return osig; - } - } - } - - if (lsig == 0) { - lsig = lexp->synthesize(des, scope); - if (lsig == 0) return 0; - delete lexp; - } - - if (rsig == 0) { - rsig = rexp->synthesize(des, scope); - if (rsig == 0) return 0; - delete rexp; - } - - unsigned dwidth = lsig->vector_width(); - if (rsig->vector_width() > dwidth) dwidth = rsig->vector_width(); - - /* Operands of binary compare need to be padded to equal - size. Figure the pad bit needed to extend the narrowest - vector. */ - if (!real_arg && lsig->vector_width() < dwidth) - lsig = pad_to_width(des, lsig, dwidth); - if (!real_arg && rsig->vector_width() < dwidth) - rsig = pad_to_width(des, rsig, dwidth); - - /* For now the runtime cannot convert a vec4 to a real value. */ - if (real_arg && (rsig->data_type() != IVL_VT_REAL || - lsig->data_type() != IVL_VT_REAL)) { - cerr << get_fileline() << ": sorry: comparing bit based signals " - "and real values is not supported." << endl; - des->errors += 1; - return 0; - } - - NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE); - osig->data_type(IVL_VT_LOGIC); - osig->set_line(*this); - osig->local_flag(true); - - NetNode*gate; - - switch (op_) { - case '<': - case '>': - case 'L': - case 'G': { - NetCompare*cmp = new - NetCompare(scope, scope->local_symbol(), dwidth); - connect(cmp->pin_DataA(), lsig->pin(0)); - connect(cmp->pin_DataB(), rsig->pin(0)); - - switch (op_) { - case '<': - connect(cmp->pin_ALB(), osig->pin(0)); - break; - case '>': - connect(cmp->pin_AGB(), osig->pin(0)); - break; - case 'L': - connect(cmp->pin_ALEB(), osig->pin(0)); - break; - case 'G': - connect(cmp->pin_AGEB(), osig->pin(0)); - break; - } - /* If both operands are signed, then do a signed - compare. */ - if (lsig->get_signed() && rsig->get_signed()) - cmp->set_signed(true); - - gate = cmp; - break; - } - - case 'E': // Case equals (===) - if (real_arg) { - cerr << get_fileline() << ": error: Case equality may not " - "have real operands." << endl; - des->errors += 1; - return 0; - } - gate = new NetCaseCmp(scope, scope->local_symbol(), dwidth, true); - connect(gate->pin(0), osig->pin(0)); - connect(gate->pin(1), lsig->pin(0)); - connect(gate->pin(2), rsig->pin(0)); - break; - - case 'N': // Case equals (!==) - if (real_arg) { - cerr << get_fileline() << ": error: Case inequality may not " - "have real operands." << endl; - des->errors += 1; - return 0; - } - gate = new NetCaseCmp(scope, scope->local_symbol(), dwidth, false); - connect(gate->pin(0), osig->pin(0)); - connect(gate->pin(1), lsig->pin(0)); - connect(gate->pin(2), rsig->pin(0)); - break; - - case 'e': // == - - /* Handle the special case of single bit compare with a - single XNOR gate. This is easy and direct. */ - if (dwidth == 1 && !real_arg){ - gate = new NetLogic(scope, scope->local_symbol(), - 3, NetLogic::XNOR, 1); - connect(gate->pin(0), osig->pin(0)); - connect(gate->pin(1), lsig->pin(0)); - connect(gate->pin(2), rsig->pin(0)); - break; - } - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate net == gate." - << endl; - } - - /* Oh well, do the general case with a NetCompare. */ - { NetCompare*cmp = new NetCompare(scope, scope->local_symbol(), - dwidth); - connect(cmp->pin_DataA(), lsig->pin(0)); - connect(cmp->pin_DataB(), rsig->pin(0)); - connect(cmp->pin_AEB(), osig->pin(0)); - gate = cmp; - } - break; - - case 'n': // != - - /* Handle the special case of single bit compare with a - single XOR gate. This is easy and direct. */ - if (dwidth == 1 && lsig->data_type() != IVL_VT_REAL && - rsig->data_type() != IVL_VT_REAL) { - gate = new NetLogic(scope, scope->local_symbol(), - 3, NetLogic::XOR, 1); - connect(gate->pin(0), osig->pin(0)); - connect(gate->pin(1), lsig->pin(0)); - connect(gate->pin(2), rsig->pin(0)); - break; - } - - /* Oh well, do the general case with a NetCompare. */ - { NetCompare*cmp = new NetCompare(scope, scope->local_symbol(), - dwidth); - connect(cmp->pin_DataA(), lsig->pin(0)); - connect(cmp->pin_DataB(), rsig->pin(0)); - connect(cmp->pin_ANEB(), osig->pin(0)); - gate = cmp; - } - break; - - default: - assert(0); - } - - gate->set_line(*this); - gate->rise_time(rise); - gate->fall_time(fall); - gate->decay_time(decay); - des->add_node(gate); - - return osig; -} - -/* - * Elaborate a divider gate. This function create a NetDivide gate - * which has exactly the right sized DataA, DataB and Result ports. If - * the l-value is wider then the result, then pad. - */ -NetNet* PEBinary::elaborate_net_div_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const -{ - NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0), - *rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0); - - if (lsig == 0 || rsig == 0) return 0; - - // Check the l-value width. If it is unspecified, then use the - // largest operand width as the l-value width. Restrict the - // result width to the width of the largest operand, because - // there is no value is excess divider. - - unsigned rwidth = lwidth; - - // If either operand is IVL_VT_REAL, then cast the other to - // IVL_VT_REAL so that the division can become IVL_VT_REAL. - - if (lsig->data_type()==IVL_VT_REAL || rsig->data_type()==IVL_VT_REAL) { - if (lsig->data_type() != IVL_VT_REAL) - lsig = cast_to_real(des, scope, lsig); - if (rsig->data_type() != IVL_VT_REAL) - rsig = cast_to_real(des, scope, rsig); - } - - if (rwidth == 0) { - rwidth = lsig->vector_width(); - if (rsig->vector_width() > rwidth) - rwidth = rsig->vector_width(); - - lwidth = rwidth; - } - - if ((rwidth > lsig->vector_width()) && (rwidth > rsig->vector_width())) { - rwidth = lsig->vector_width(); - if (rsig->vector_width() > rwidth) - rwidth = rsig->vector_width(); - } - - /* The arguments of a divide must have the same type. */ - if (lsig->data_type() != rsig->data_type()) { - cerr << get_fileline() << ": error: Arguments of divide " - << "have different data types." << endl; - cerr << get_fileline() << ": : Left argument is " - << lsig->data_type() << ", right argument is " - << rsig->data_type() << "." << endl; - des->errors += 1; - return 0; - } - - // Create a device with the calculated dimensions. - NetDivide*div = new NetDivide(scope, scope->local_symbol(), rwidth, - lsig->vector_width(), - rsig->vector_width()); - div->set_line(*this); - div->rise_time(rise); - div->fall_time(fall); - div->decay_time(decay); - des->add_node(div); - - div->set_signed(lsig->get_signed() && rsig->get_signed()); - - // Connect the left and right inputs of the divider to the - // nets that are the left and right expressions. - - connect(div->pin_DataA(), lsig->pin(0)); - connect(div->pin_DataB(), rsig->pin(0)); - - - // Make an output signal that is the width of the l-value. - // Due to above calculation of rwidth, we know that the result - // will be no more than the l-value, so it is safe to connect - // all the result pins to the osig. - - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, lwidth); - osig->local_flag(true); - osig->set_line(*this); - osig->data_type( lsig->data_type() ); - osig->set_signed(div->get_signed()); - - connect(div->pin_Result(), osig->pin(0)); - - - return osig; -} - -/* - * Elaborate a modulo gate. - */ -NetNet* PEBinary::elaborate_net_mod_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const -{ - NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0), - *rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0); - - if (lsig == 0 || rsig == 0) return 0; - - /* The arguments of a modulus must have the same type. */ - if (lsig->data_type() != rsig->data_type()) { - cerr << get_fileline() << ": error: Arguments of modulus " - << "have different data types." << endl; - cerr << get_fileline() << ": : Left argument is " - << lsig->data_type() << ", right argument is " - << rsig->data_type() << "." << endl; - des->errors += 1; - return 0; - } - - /* The % operator does not support real arguments in baseline - Verilog. But we allow it in our extended form of Verilog. */ - if (gn_icarus_misc_flag==false && lsig->data_type() == IVL_VT_REAL) { - cerr << get_fileline() << ": error: Modulus operator may not " - "have REAL operands." << endl; - des->errors += 1; - return 0; - } - - /* rwidth is result width. */ - unsigned rwidth = lwidth; - if (rwidth == 0) { - /* Reals are always 1 wide and lsig/rsig types match here. */ - if (lsig->data_type() == IVL_VT_REAL) { - lwidth = 1; - rwidth = 1; - } else { - rwidth = lsig->vector_width(); - if (rsig->vector_width() > rwidth) - rwidth = rsig->vector_width(); - - lwidth = rwidth; - } - } - - NetModulo*mod = new NetModulo(scope, scope->local_symbol(), rwidth, - lsig->vector_width(), - rsig->vector_width()); - mod->set_line(*this); - mod->rise_time(rise); - mod->fall_time(fall); - mod->decay_time(decay); - des->add_node(mod); - - connect(mod->pin_DataA(), lsig->pin(0)); - connect(mod->pin_DataB(), rsig->pin(0)); - - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, rwidth); - osig->set_line(*this); - osig->data_type( lsig->data_type() ); - osig->local_flag(true); - - connect(mod->pin_Result(), osig->pin(0)); - - return osig; -} - -NetNet* PEBinary::elaborate_net_log_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const -{ - NetNet*lsig = left_->elaborate_net(des, scope, 0, 0, 0, 0), - *rsig = right_->elaborate_net(des, scope, 0, 0, 0, 0); - - if (lsig == 0 || rsig == 0) return 0; - - if (rsig->data_type() == IVL_VT_REAL || - lsig->data_type() == IVL_VT_REAL) { - cerr << get_fileline() << ": sorry: " << human_readable_op(op_) - << " is currently unsupported for real values." << endl; - des->errors += 1; - return 0; - } - - NetLogic*gate; - switch (op_) { - case 'a': - gate = new NetLogic(scope, scope->local_symbol(), - 3, NetLogic::AND, 1); - break; - case 'o': - gate = new NetLogic(scope, scope->local_symbol(), - 3, NetLogic::OR, 1); - break; - default: - assert(0); - } - - // The first OR gate returns 1 if the left value is true... - if (lsig->vector_width() > 1) { - NetUReduce*gate_tmp = new NetUReduce(scope, scope->local_symbol(), - NetUReduce::OR, - lsig->vector_width()); - connect(gate_tmp->pin(1), lsig->pin(0)); - connect(gate->pin(1), gate_tmp->pin(0)); - - /* The reduced logical value is a new nexus, create a - temporary signal to represent it. */ - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, 1); - tmp->data_type(IVL_VT_LOGIC); - tmp->local_flag(true); - connect(gate->pin(1), tmp->pin(0)); - - des->add_node(gate_tmp); - - } else { - connect(gate->pin(1), lsig->pin(0)); - } - - // The second OR gate returns 1 if the right value is true... - if (rsig->vector_width() > 1) { - NetUReduce*gate_tmp = new NetUReduce(scope, scope->local_symbol(), - NetUReduce::OR, - rsig->vector_width()); - connect(gate_tmp->pin(1), rsig->pin(0)); - connect(gate->pin(2), gate_tmp->pin(0)); - - /* The reduced logical value is a new nexus, create a - temporary signal to represent it. */ - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, 1); - tmp->data_type(IVL_VT_LOGIC); - tmp->local_flag(true); - connect(gate->pin(2), tmp->pin(0)); - - des->add_node(gate_tmp); - - } else { - connect(gate->pin(2), rsig->pin(0)); - } - - // The output is the AND/OR of the two logic values. - NetNet*osig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE); - osig->local_flag(true); - osig->data_type(IVL_VT_LOGIC); - connect(gate->pin(0), osig->pin(0)); - - gate->set_line(*this); - gate->rise_time(rise); - gate->fall_time(fall); - gate->decay_time(decay); - des->add_node(gate); - return osig; -} - -NetNet* PEBinary::elaborate_net_mul_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const -{ - verinum*lnum = left_->eval_const(des, scope); - verinum*rnum = right_->eval_const(des, scope); - - /* Detect and handle the special case that both the operands - of the multiply are constant expressions. Evaluate the - value and make this a simple constant. */ - if (lnum && rnum) { - verinum prod = *lnum * *rnum; - if (lwidth == 0) - lwidth = prod.len(); - - verinum res (verinum::V0, lwidth); - for (unsigned idx = 0 - ; idx < prod.len() && idx < lwidth - ; idx += 1) { - res.set(idx, prod.get(idx)); - } - - NetConst*odev = new NetConst(scope, scope->local_symbol(), res); - des->add_node(odev); - odev->rise_time(rise); - odev->fall_time(fall); - odev->decay_time(decay); - odev->set_line(*this); - - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, lwidth); - osig->set_line(*this); - osig->local_flag(true); - osig->data_type(IVL_VT_LOGIC); - - connect(odev->pin(0), osig->pin(0)); - - return osig; - } - - NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0), - *rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0); - - if (lsig == 0 || rsig == 0) return 0; - - /* The arguments of a multiply must have the same type. */ - if (lsig->data_type() != rsig->data_type()) { - cerr << get_fileline() << ": error: Arguments of multiply " - << "have different data types." << endl; - cerr << get_fileline() << ": : Left argument is " - << lsig->data_type() << ", right argument is " - << rsig->data_type() << "." << endl; - des->errors += 1; - return 0; - } - - // The mult is signed if both its operands are signed. - bool arith_is_signed = lsig->get_signed() && rsig->get_signed(); - - unsigned rwidth = lwidth; - if (rwidth == 0) { - /* Reals are always 1 wide and lsig/rsig types match here. */ - if (lsig->data_type() == IVL_VT_REAL) { - rwidth = 1; - lwidth = 1; - } else { - rwidth = lsig->vector_width() + rsig->vector_width(); - lwidth = rwidth; - } - } - - if (arith_is_signed) { - lsig = pad_to_width_signed(des, lsig, rwidth); - rsig = pad_to_width_signed(des, rsig, rwidth); - } - - NetMult*mult = new NetMult(scope, scope->local_symbol(), rwidth, - lsig->vector_width(), - rsig->vector_width()); - mult->set_line(*this); - mult->rise_time(rise); - mult->fall_time(fall); - mult->decay_time(decay); - des->add_node(mult); - - mult->set_signed( arith_is_signed ); - - connect(mult->pin_DataA(), lsig->pin(0)); - connect(mult->pin_DataB(), rsig->pin(0)); - - /* Make a signal to carry the output from the multiply. */ - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, rwidth); - osig->data_type( lsig->data_type() ); - osig->local_flag(true); - connect(mult->pin_Result(), osig->pin(0)); - - return osig; -} - -NetNet* PEBinary::elaborate_net_pow_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const -{ - NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0), - *rsig = right_->elaborate_net(des, scope, lwidth, 0, 0, 0); - - if (lsig == 0 || rsig == 0) return 0; - - /* The arguments of a power must have the same type. */ - if (lsig->data_type() != rsig->data_type()) { - cerr << get_fileline() << ": error: Arguments of power " - << "have different data types." << endl; - cerr << get_fileline() << ": : Left argument is " - << lsig->data_type() << ", right argument is " - << rsig->data_type() << "." << endl; - des->errors += 1; - return 0; - } - - /* The power is signed if either of its operands are signed. */ - bool arith_is_signed = lsig->get_signed() || rsig->get_signed(); - - unsigned rwidth = lwidth; - if (rwidth == 0) { - /* Reals are always 1 wide and lsig/rsig types match here. */ - if (lsig->data_type() == IVL_VT_REAL) { - rwidth = 1; - lwidth = 1; - } else { - /* This is incorrect! a * (2^b - 1) is close. */ - rwidth = lsig->vector_width() + rsig->vector_width(); - lwidth = rwidth; - } - } - - if (arith_is_signed) { - lsig = pad_to_width_signed(des, lsig, rwidth); - rsig = pad_to_width_signed(des, rsig, rwidth); - } - - NetPow*powr = new NetPow(scope, scope->local_symbol(), rwidth, - lsig->vector_width(), - rsig->vector_width()); - powr->set_line(*this); - powr->rise_time(rise); - powr->fall_time(fall); - powr->decay_time(decay); - des->add_node(powr); - - powr->set_signed( arith_is_signed ); - - connect(powr->pin_DataA(), lsig->pin(0)); - connect(powr->pin_DataB(), rsig->pin(0)); - - /* Make a signal to carry the output from the power. */ - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, rwidth); - osig->data_type( lsig->data_type() ); - osig->local_flag(true); - connect(powr->pin_Result(), osig->pin(0)); - - return osig; -} - -NetNet* PEBinary::elaborate_net_shift_(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay) const -{ - NetNet*lsig = left_->elaborate_net(des, scope, lwidth, 0, 0, 0); - - if (lsig == 0) return 0; - - /* Cannot shift a real value. */ - if (lsig->data_type() == IVL_VT_REAL) { - cerr << get_fileline() << ": error: shift operators (" - << human_readable_op(op_) - << ") cannot shift a real value." << endl; - des->errors += 1; - return 0; - } - - if (lsig->vector_width() > lwidth) - lwidth = lsig->vector_width(); - - bool right_flag = op_ == 'r' || op_ == 'R'; - bool signed_flag = op_ == 'R'; - - /* Handle the special case of a constant shift amount. There - is no reason in this case to create a gate at all, just - connect the lsig to the osig with the bit positions - shifted. Use a NetPartSelect to select the parts of the - left expression that survive the shift, and a NetConcat to - concatenate a constant for padding. */ - if (verinum*rval = right_->eval_const(des, scope)) { - assert(rval->is_defined()); - unsigned dist = rval->as_ulong(); - - /* Very special case: constant 0 shift. Simply return - the left signal again. */ - if (dist == 0) return lsig; - - /* The construction that I'm making will ultimately - connect its output to the osig here. This will be the - result that I return from this function. */ - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, lwidth); - osig->data_type( lsig->data_type() ); - osig->local_flag(true); - - - /* Make the constant zero's that I'm going to pad to the - top or bottom of the left expression. Attach a signal - to its output so that I don't have to worry about it - later. If the left expression is less than the - desired width (and we are doing right shifts) then we - can combine the expression padding with the distance - padding to reduce nodes. */ - unsigned pad_width = dist; - unsigned part_width = lwidth - dist; - if (op_ == 'r' || op_ == 'R') { - if (lsig->vector_width() < lwidth) { - pad_width += lwidth - lsig->vector_width(); - part_width -= lwidth - lsig->vector_width(); - } - } else { - - /* The left net must be the same width as the - result. The part select that I'm about to make relies - on that. */ - lsig = pad_to_width(des, lsig, lwidth); - - } - - NetNet*zero = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, pad_width); - zero->data_type( lsig->data_type() ); - zero->local_flag(true); - zero->set_line(*this); - - /* Padding bits are zero in most cases, but copies of - * the sign bit in the case of a signed right shift */ - if (op_ == 'R') { - NetPartSelect*sign_bit - = new NetPartSelect(lsig, lsig->vector_width()-1, - 1, NetPartSelect::VP); - des->add_node(sign_bit); - NetReplicate*sign_pad - = new NetReplicate(scope, scope->local_symbol(), - pad_width, pad_width); - des->add_node(sign_pad); - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, 1); - tmp->data_type( lsig->data_type() ); - tmp->local_flag(true); - tmp->set_line(*this); - connect(sign_bit->pin(0), tmp->pin(0)); - connect(sign_bit->pin(0), sign_pad->pin(1)); - - connect(zero->pin(0), sign_pad->pin(0)); - - } else { - NetConst*zero_c = new NetConst(scope, scope->local_symbol(), - verinum(verinum::V0, pad_width)); - des->add_node(zero_c); - connect(zero->pin(0), zero_c->pin(0)); - } - - /* If all data bits get shifted away, connect the zero or - * padding bits directly to output, and stop before building the - * concatenation. */ - if (dist >= lwidth) { - connect(osig->pin(0), zero->pin(0)); - return osig; - } - - /* Make a concatenation operator that will join the - part-selected right expression at the pad values. */ - NetConcat*cc = new NetConcat(scope, scope->local_symbol(), - lwidth, 2); - cc->set_line(*this); - des->add_node(cc); - connect(cc->pin(0), osig->pin(0)); - - /* Make the part select of the left expression and - connect it to the LSB or MSB of the concatenation, - depending on the direction of the shift. */ - NetPartSelect*part; - - switch (op_) { - case 'l': // Left shift === {lsig, zero} - part = new NetPartSelect(lsig, 0, part_width, - NetPartSelect::VP); - connect(cc->pin(1), zero->pin(0)); - connect(cc->pin(2), part->pin(0)); - break; - case 'R': - case 'r': // right-shift === {zero, lsig} - part = new NetPartSelect(lsig, dist, part_width, - NetPartSelect::VP); - connect(cc->pin(1), part->pin(0)); - connect(cc->pin(2), zero->pin(0)); - break; - default: - assert(0); - } - - part->set_line(*this); - part->rise_time(rise); - part->fall_time(fall); - part->decay_time(decay); - des->add_node(part); - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate shift " - << "(" << op_ << ") as concatenation of " - << pad_width << " zeros with " << part_width - << " bits of expression." << endl; - } - - /* Attach a signal to the part select output (NetConcat - input) */ - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, part_width); - tmp->data_type( lsig->data_type() ); - tmp->local_flag(true); - tmp->set_line(*this); - connect(part->pin(0), tmp->pin(0)); - - return osig; - } - - // Calculate the number of useful bits for the shift amount, - // and elaborate the right_ expression as the shift amount. - unsigned dwid = 0; - while ((1U << dwid) < lwidth) - dwid += 1; - - NetNet*rsig = right_->elaborate_net(des, scope, dwid, 0, 0, 0); - - if (rsig == 0) return 0; - - /* You cannot shift a value by a real amount. */ - if (rsig->data_type() == IVL_VT_REAL) { - cerr << get_fileline() << ": error: shift operators " - "cannot shift by a real value." << endl; - des->errors += 1; - return 0; - } - - // Make the shift device itself, and the output - // NetNet. Connect the Result output pins to the osig signal - NetCLShift*gate = new NetCLShift(scope, scope->local_symbol(), - lwidth, rsig->vector_width(), - right_flag, signed_flag); - gate->set_line(*this); - gate->rise_time(rise); - gate->fall_time(fall); - gate->decay_time(decay); - des->add_node(gate); - - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, lwidth); - osig->data_type( lsig->data_type() ); - osig->local_flag(true); - osig->set_signed(signed_flag); - - connect(osig->pin(0), gate->pin_Result()); - - // Connect the lsig (the left expression) to the Data input, - // and pad it if necessary. The lwidth is the width of the - // NetCLShift gate, and the D input must match. - if (lsig->vector_width() < lwidth) - lsig = pad_to_width(des, lsig, lwidth); - - assert(lsig->vector_width() <= lwidth); - connect(lsig->pin(0), gate->pin_Data()); - - // Connect the rsig (the shift amount expression) to the - // Distance input. - connect(rsig->pin(0), gate->pin_Distance()); - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: " - << "Elaborate LPM_SHIFT: width="<width() - << ", swidth="<< gate->width_dist() << endl; - } - - return osig; -} - -/* - * This method elaborates a call to a function in the context of a - * continuous assignment. The definition of the function contains a - * list of the ports, and an output port. The NetEUFunc that I create - * here has a port for all the input ports and the output port. The - * ports are connected by pins. - */ -NetNet* PECallFunction::elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - unsigned errors = 0; - unsigned func_pins = 0; - - if (path_.front().name[0] == '$') - return elaborate_net_sfunc_(des, scope, - width, rise, fall, decay, - drive0, drive1); - - - /* Look up the function definition. */ - NetFuncDef*def = des->find_function(scope, path_); - if (def == 0) { - cerr << get_fileline() << ": error: No function " << path_ << - " in this context (" << scope_path(scope) << ")." << endl; - des->errors += 1; - return 0; - } - - NetScope*dscope = def->scope(); - assert(dscope); - - /* This must be a function that returns a signal. */ - assert(def->return_sig()); - - /* check the validity of the parameters. */ - if (! check_call_matches_definition_(des, dscope)) - return 0; - - /* Elaborate all the parameters of the function call, - and collect the resulting NetNet objects. All the - parameters take on the size of the target port. */ - - svector eparms (def->port_count()); - for (unsigned idx = 0 ; idx < eparms.count() ; idx += 1) { - const NetNet* port_reg = def->port(idx); - NetNet*tmp = parms_[idx]->elaborate_net(des, scope, - port_reg->vector_width(), - 0, 0, 0, - Link::STRONG, - Link::STRONG); - if (tmp == 0) { - cerr << get_fileline() << ": error: Unable to elaborate " - << "port " << idx << " of call to " << path_ << - "." << endl; - errors += 1; - des->errors += 1; - continue; - } - - func_pins += tmp->pin_count(); - eparms[idx] = tmp; - } - - if (errors > 0) return 0; - - NetUserFunc*net = new NetUserFunc(scope, - scope->local_symbol(), - dscope); - net->set_line(*this); - net->rise_time(rise); - net->fall_time(fall); - net->decay_time(decay); - des->add_node(net); - - /* Create an output signal and connect it to the output pins - of the function net. */ - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, - def->return_sig()->vector_width()); - osig->local_flag(true); - osig->data_type(def->return_sig()->data_type()); - - connect(net->pin(0), osig->pin(0)); - - /* Connect the parameter pins to the parameter expressions. */ - for (unsigned idx = 0 ; idx < eparms.count() ; idx += 1) { - const NetNet* port = def->port(idx); - NetNet*cur = eparms[idx]; - - NetNet*tmp = pad_to_width(des, cur, port->vector_width()); - - connect(net->pin(idx+1), tmp->pin(0)); - } - - return osig; -} - -NetNet* PECallFunction::elaborate_net_sfunc_(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - perm_string name = peek_tail_name(path_); - - /* Handle the special case that the function call is to - $signed. This takes a single expression argument, and - forces it to be a signed result. Otherwise, it is as if the - $signed did not exist. */ - if (strcmp(name, "$signed") == 0) { - if ((parms_.size() != 1) || (parms_[0] == 0)) { - cerr << get_fileline() << ": error: The $signed() function " - << "takes exactly one(1) argument." << endl; - des->errors += 1; - return 0; - } - - PExpr*expr = parms_[0]; - NetNet*sub = expr->elaborate_net(des, scope, width, rise, - fall, decay, drive0, drive1); - sub->set_signed(true); - return sub; - } - - /* handle $unsigned like $signed */ - if (strcmp(name, "$unsigned") == 0) { - if ((parms_.size() != 1) || (parms_[0] == 0)) { - cerr << get_fileline() << ": error: The $unsigned() function " - << "takes exactly one(1) argument." << endl; - des->errors += 1; - return 0; - } - - PExpr*expr = parms_[0]; - NetNet*sub = expr->elaborate_net(des, scope, width, rise, - fall, decay, drive0, drive1); - sub->set_signed(false); - return sub; - } - - 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 " - << peek_tail_name(path_) << " 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+parms_.size()); - net->set_line(*this); - net->rise_time(rise); - net->fall_time(fall); - net->decay_time(decay); - 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 < parms_.size() ; idx += 1) { - NetNet*tmp = parms_[idx]->elaborate_net(des, scope, 0, - 0, 0, 0, - Link::STRONG, Link::STRONG); - if (tmp == 0) { - cerr << get_fileline() << ": error: Unable to elaborate " - << "port " << idx << " of call to " << path_ << - "." << endl; - errors += 1; - des->errors += 1; - continue; - } - - connect(net->pin(1+idx), tmp->pin(0)); - } - - if (errors > 0) return 0; - - return osig; -} - - -/* - * The concatenation operator, as a net, is a wide signal that is - * connected to all the pins of the elaborated expression nets. - */ -NetNet* PEConcat::elaborate_net(Design*des, NetScope*scope, - unsigned, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - svectornets (parms_.count()); - unsigned vector_width = 0; - unsigned errors = 0; - unsigned repeat = 1; - - /* The repeat expression must evaluate to a compile-time - constant. This is used to generate the width of the - concatenation. */ - if (repeat_) { - NetExpr*etmp = elab_and_eval(des, scope, repeat_, -1); - assert(etmp); - NetEConst*erep = dynamic_cast(etmp); - - if (erep == 0) { - cerr << get_fileline() << ": error: Unable to " - << "evaluate constant repeat expression." << endl; - des->errors += 1; - return 0; - } - - if (!erep->value().is_defined()) { - cerr << get_fileline() << ": error: Concatenation repeat " - << "may not be undefined (" << erep->value() - << ")." << endl; - des->errors += 1; - return 0; - } - - if (erep->value().is_negative()) { - cerr << get_fileline() << ": error: Concatenation repeat " - << "may not be negative (" << erep->value().as_long() - << ")." << endl; - des->errors += 1; - return 0; - } - - repeat = erep->value().as_ulong(); - delete etmp; - - if (repeat == 0) { - cerr << get_fileline() << ": error: Concatenation repeat " - "may not be zero." - << endl; - des->errors += 1; - return 0; - } - } - - if (debug_elaborate) { - cerr << get_fileline() <<": debug: PEConcat concatenation repeat=" - << repeat << "." << endl; - } - - /* The operands of the concatenation must contain all - self-determined arguments. Set this flag to force an error - message if this is not the case. */ - const bool save_flag = must_be_self_determined_flag; - must_be_self_determined_flag = true; - - /* Elaborate the operands of the concatenation. */ - for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) { - - if (parms_[idx] == 0) { - cerr << get_fileline() << ": error: Empty expressions " - << "not allowed in concatenations." << endl; - errors += 1; - continue; - } - - /* Look for the special case of an unsized number in a - concatenation expression. Mark this as an error, but - allow elaboration to continue to see if I can find - more errors. */ - - if (PENumber*tmp = dynamic_cast(parms_[idx])) { - if (tmp->value().has_len() == false) { - cerr << get_fileline() << ": error: Number " - << tmp->value() << " with indefinite size" - << " in concatenation." << endl; - errors += 1; - } - } - - nets[idx] = parms_[idx]->elaborate_net(des, scope, 0, 0, 0, 0); - if (nets[idx] == 0) - errors += 1; - else - vector_width += nets[idx]->vector_width(); - } - - must_be_self_determined_flag = save_flag; - - /* If any of the sub expressions failed to elaborate, then - delete all those that did and abort myself. */ - if (errors) { - for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) { - if (nets[idx]) delete nets[idx]; - } - des->errors += errors; - return 0; - } - - if (debug_elaborate) { - cerr << get_fileline() <<": debug: PEConcat concat collected " - << "width=" << vector_width << ", repeat=" << repeat - << " of " << nets.count() << " expressions." << endl; - } - - NetConcat*dev = new NetConcat(scope, scope->local_symbol(), - vector_width*repeat, - nets.count()*repeat); - dev->set_line(*this); - dev->rise_time(rise); - dev->fall_time(fall); - dev->decay_time(decay); - des->add_node(dev); - - /* Make the temporary signal that connects to all the - operands, and connect it up. Scan the operands of the - concat operator from least significant to most significant, - which is opposite from how they are given in the list. - - Allow for a repeat count other than 1 by repeating the - connect loop as many times as necessary. */ - - NetNet*osig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, vector_width * repeat); - osig->data_type(IVL_VT_LOGIC); - - connect(dev->pin(0), osig->pin(0)); - - unsigned cur_pin = 1; - for (unsigned rpt = 0; rpt < repeat ; rpt += 1) { - for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) { - NetNet*cur = nets[nets.count()-idx-1]; - connect(dev->pin(cur_pin++), cur->pin(0)); - } - } - - osig->local_flag(true); - return osig; -} - -/* - * This private method handles the special case that we have a - * non-constant bit-select of an identifier. We already know that the - * signal that is represented is "sig". - */ -NetNet* PEIdent::elaborate_net_bitmux_(Design*des, NetScope*scope, - NetNet*sig, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - const name_component_t&name_tail = path_.back(); - ivl_assert(*this, !name_tail.index.empty()); - - const index_component_t&index_tail = name_tail.index.back(); - ivl_assert(*this, index_tail.sel == index_component_t::SEL_BIT); - ivl_assert(*this, index_tail.msb != 0); - ivl_assert(*this, index_tail.lsb == 0); - - /* Elaborate the selector. */ - NetNet*sel; - - if (sig->msb() < sig->lsb()) { - NetExpr*sel_expr = index_tail.msb->elaborate_expr(des, scope, -1, false); - sel_expr = make_sub_expr(sig->lsb(), sel_expr); - eval_expr(sel_expr); - - 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, scope); - - } else { - sel = index_tail.msb->elaborate_net(des, scope, 0, 0, 0, 0); - } - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Create NetPartSelect " - << "using signal " << sel->name() << " as selector" - << endl; - } - - /* Create a part select that takes a non-constant offset and a - width of 1. */ - NetPartSelect*mux = new NetPartSelect(sig, sel, 1); - des->add_node(mux); - mux->set_line(*this); - - NetNet*out = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, 1); - out->data_type(sig->data_type()); - - connect(out->pin(0), mux->pin(0)); - return out; -} - -NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - ivl_assert(*this, scope); - - const name_component_t&name_tail = path_.back(); - - NetNet* sig = 0; - const NetExpr*par = 0; - NetEvent* eve = 0; - - const NetExpr*id_msb; - const NetExpr*id_lsb; - symbol_search(des, scope, path_, sig, par, eve, id_msb, id_lsb); - - /* If this is a parameter name, then create a constant node - that connects to a signal with the correct name. */ - if (par != 0) { - - // Detect and handle the special case that we have a - // real valued parameter. Return a NetLiteral and a - // properly typed net. - if (const NetECReal*pc = dynamic_cast(par)) { - NetLiteral*tmp = new NetLiteral(scope, scope->local_symbol(), - pc->value()); - des->add_node(tmp); - tmp->set_line(*par); - sig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT); - sig->set_line(*tmp); - sig->data_type(tmp->data_type()); - sig->local_flag(true); - - connect(tmp->pin(0), sig->pin(0)); - return sig; - } - - const NetEConst*pc = dynamic_cast(par); - if (pc == 0) { - cerr << get_fileline() << ": internal error: " - << "Non-consant parameter value?: " << *par << endl; - cerr << get_fileline() << ": : " - << "Expression type is " << par->expr_type() << endl; - } - ivl_assert(*this, pc); - verinum pvalue = pc->value(); - - /* If the parameter has declared dimensions, then apply - those to the dimensions of the net that we create. */ - long msb = pvalue.len()-1; - long lsb = 0; - if (id_msb || id_lsb) { - assert(id_msb && id_lsb); - const NetEConst*tmp = dynamic_cast(id_msb); - ivl_assert(*this, tmp); - msb = tmp->value().as_long(); - - tmp = dynamic_cast(id_lsb); - ivl_assert(*this, tmp); - lsb = tmp->value().as_long(); - } - - /* If the constant is smaller than its defined width extend - the value. If needed this will be padded later to fit - the real signal width. */ - unsigned pwidth = msb > lsb ? msb - lsb : lsb - msb; - if (pwidth > pvalue.len()) { - verinum tmp ((uint64_t)0, pwidth); - for (unsigned idx = 0 ; idx < pvalue.len() ; idx += 1) - tmp.set(idx, pvalue.get(idx)); - - pvalue = tmp; - } - - sig = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, msb, lsb); - sig->set_line(*this); - sig->data_type(IVL_VT_LOGIC); - sig->local_flag(true); - NetConst*cp = new NetConst(scope, scope->local_symbol(), - pvalue); - cp->set_line(*this); - des->add_node(cp); - for (unsigned idx = 0; idx < sig->pin_count(); idx += 1) - connect(sig->pin(idx), cp->pin(idx)); - } - - /* Check for the error case that the name is not found, and it - is hierarchical. We can't just create a name in another - scope, it's just not allowed. */ - if (sig == 0 && path_.size() != 1) { - cerr << get_fileline() << ": error: The hierarchical name " - << path_ << " is undefined in " - << scope_path(scope) << "." << endl; - - pform_name_t tmp_path = path_; - tmp_path.pop_back(); - - list stmp_path = eval_scope_path(des, scope, tmp_path); - NetScope*tmp_scope = des->find_scope(scope, stmp_path); - if (tmp_scope == 0) { - cerr << get_fileline() << ": : I can't even find " - << "the scope " << tmp_path << "." << endl; - } - - des->errors += 1; - return 0; - } - - /* Fallback, this may be an implicitly declared net. */ - if (sig == 0) { - NetNet::Type nettype = scope->default_nettype(); - sig = new NetNet(scope, name_tail.name, - nettype, 1); - sig->data_type(IVL_VT_LOGIC); - - if (error_implicit || (nettype == NetNet::NONE)) { - cerr << get_fileline() << ": error: " - << scope_path(scope) << "." << name_tail.name - << " not defined in this scope." << endl; - des->errors += 1; - - } else if (warn_implicit) { - cerr << get_fileline() << ": warning: implicit " - "definition of wire " << scope_path(scope) - << "." << name_tail.name << "." << endl; - } - } - - ivl_assert(*this, sig); - - /* Handle the case that this is an array elsewhere. */ - if (sig->array_dimensions() > 0) { - if (name_tail.index.size() == 0) { - cerr << get_fileline() << ": error: Array " << sig->name() - << " cannot be used here without an index." << endl; - des->errors += 1; - return 0; - } - - return elaborate_net_array_(des, scope, sig, lwidth, - rise, fall, decay, - drive0, drive1); - } - - return elaborate_net_net_(des, scope, sig, lwidth, - rise, fall, decay, drive0, drive1); - -} - -NetNet* PEIdent::process_select_(Design*des, NetScope*scope, - NetNet*sig) const -{ - - // If there are more index items then there are array - // dimensions, then treat them as word part selects. For - // example, if this is a memory array, then array dimensions - // is the first and part select the remainder. - long midx, lidx; - if (! eval_part_select_(des, scope, sig, midx, lidx)) - return sig; - - ivl_assert(*this, lidx >= 0); - unsigned part_count = midx-lidx+1; - - // Maybe this is a full-width constant part select? If - // so, do nothing. - if (part_count == sig->vector_width()) - return sig; - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate part select" - << " of word from " << sig->name() << "[base="<set_line(*sig); - des->add_node(ps); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, part_count-1, 0); - tmp->data_type( sig->data_type() ); - tmp->local_flag(true); - connect(tmp->pin(0), ps->pin(0)); - - return tmp; -} - -NetNet* PEIdent::elaborate_net_net_(Design*des, NetScope*scope, - NetNet*sig, unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - 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; - - switch (use_sel) { - case index_component_t::SEL_IDX_UP: - case index_component_t::SEL_IDX_DO: - return elaborate_net_net_idx_up_(des, scope, sig, lwidth, - rise, fall, decay, drive0, drive1); - - default: - break; - } - - /* Catch the case of a non-constant bit select. That should be - handled elsewhere. */ - if (use_sel == index_component_t::SEL_BIT) { - const index_component_t&index_tail = name_tail.index.back(); - - verinum*mval = index_tail.msb->eval_const(des, scope); - if (mval == 0) { - return elaborate_net_bitmux_(des, scope, sig, rise, - fall, decay, drive0, drive1); - } - - delete mval; - } - - long midx, lidx; - if (! eval_part_select_(des, scope, sig, midx, lidx)) - return 0; - - unsigned part_count = midx-lidx+1; - unsigned output_width = part_count; - - /* Detect and handle the special case that the entire part - select is outside the range of the signal. Return a - constant xxx. */ - if (midx < 0 || lidx >= (long)sig->vector_width()) { - ivl_assert(*this, sig->data_type() == IVL_VT_LOGIC); - verinum xxx (verinum::Vx, part_count); - NetConst*con = new NetConst(scope, scope->local_symbol(), xxx); - con->set_line(*sig); - des->add_node(con); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, part_count-1, 0); - tmp->data_type( sig->data_type() ); - tmp->local_flag(true); - connect(tmp->pin(0), con->pin(0)); - return tmp; - } - - NetNet*below = 0; - if (lidx < 0) { - ivl_assert(*this, sig->data_type() == IVL_VT_LOGIC); - unsigned xxx_wid = 0-lidx; - verinum xxx (verinum::Vx, xxx_wid); - NetConst*con = new NetConst(scope, scope->local_symbol(), xxx); - con->set_line(*sig); - des->add_node(con); - - below = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, xxx_wid); - below->data_type( sig->data_type() ); - below->local_flag(true); - connect(below->pin(0), con->pin(0)); - - lidx = 0; - part_count = midx-lidx+1; - } - - NetNet*above = 0; - if (midx >= (long)sig->vector_width()) { - ivl_assert(*this, sig->data_type() == IVL_VT_LOGIC); - unsigned xxx_wid = midx - sig->vector_width() + 1; - verinum xxx (verinum::Vx, xxx_wid); - NetConst*con = new NetConst(scope, scope->local_symbol(), xxx); - con->set_line(*sig); - des->add_node(con); - - above = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, xxx_wid); - above->data_type( sig->data_type() ); - above->local_flag(true); - connect(above->pin(0), con->pin(0)); - - midx = sig->vector_width()-1; - part_count = midx-lidx+1; - } - - ivl_assert(*this, lidx >= 0); - if (part_count != sig->vector_width()) { - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate part select " - << sig->name() << "[base="<set_line(*sig); - des->add_node(ps); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, part_count-1, 0); - tmp->data_type( sig->data_type() ); - tmp->local_flag(true); - connect(tmp->pin(0), ps->pin(0)); - - sig = tmp; - } - - unsigned segment_count = 1; - if (below) segment_count += 1; - if (above) segment_count += 1; - if (segment_count > 1) { - NetConcat*cc = new NetConcat(scope, scope->local_symbol(), - output_width, segment_count); - cc->set_line(*sig); - des->add_node(cc); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, output_width); - tmp->data_type( sig->data_type() ); - tmp->local_flag(true); - connect(tmp->pin(0), cc->pin(0)); - - unsigned pdx = 1; - if (below) { - connect(cc->pin(pdx), below->pin(0)); - pdx += 1; - } - connect(cc->pin(pdx), sig->pin(0)); - pdx += 1; - if (above) { - connect(cc->pin(pdx), above->pin(0)); - pdx += 1; - } - ivl_assert(*sig, segment_count == pdx-1); - - sig = tmp; - } - - return sig; -} - -NetNet* PEIdent::elaborate_net_net_idx_up_(Design*des, NetScope*scope, - NetNet*sig, unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - const name_component_t&name_tail = path_.back(); - ivl_assert(*this, !name_tail.index.empty()); - - const index_component_t&index_tail = name_tail.index.back(); - ivl_assert(*this, index_tail.lsb != 0); - ivl_assert(*this, index_tail.msb != 0); - - NetExpr*base = elab_and_eval(des, scope, index_tail.msb, -1); - - unsigned long wid = 0; - calculate_up_do_width_(des, scope, wid); - - bool down_flag = name_tail.index.back().sel==index_component_t::SEL_IDX_DO; - - // Handle the special case that the base is constant as - // well. In this case it can be converted to a conventional - // part select. - if (NetEConst*base_c = dynamic_cast (base)) { - long lsv = base_c->value().as_long(); - - // convert from -: to +: form. - if (down_flag) lsv -= (wid-1); - - // If the part select covers exactly the entire - // vector, then do not bother with it. Return the - // signal itself. - if (sig->sb_to_idx(lsv) == 0 && wid == sig->vector_width()) - return sig; - - NetPartSelect*sel = new NetPartSelect(sig, sig->sb_to_idx(lsv), - wid, NetPartSelect::VP); - sel->set_line(*this); - des->add_node(sel); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, wid); - tmp->set_line(*this); - tmp->data_type(sig->data_type()); - connect(tmp->pin(0), sel->pin(0)); - - delete base; - return tmp; - } - - if (sig->msb() > sig->lsb()) { - long offset = sig->lsb(); - if (down_flag) - offset += (wid-1); - if (offset != 0) - base = make_add_expr(base, 0-offset); - } else { - long vwid = sig->lsb() - sig->msb() + 1; - long offset = sig->msb(); - if (down_flag) - offset += (wid-1); - base = make_sub_expr(vwid-offset-wid, base); - } - - NetPartSelect*sel = new NetPartSelect(sig, base->synthesize(des, scope), wid); - sel->set_line(*this); - des->add_node(sel); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, wid); - tmp->set_line(*this); - tmp->data_type(sig->data_type()); - connect(tmp->pin(0), sel->pin(0)); - - delete base; - return tmp; -} - -NetNet* PEIdent::elaborate_net_array_(Design*des, NetScope*scope, - NetNet*sig, unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - const name_component_t&name_tail = path_.back(); - ivl_assert(*this, name_tail.index.size() >= 1); - const index_component_t&index_head = name_tail.index.front(); - ivl_assert(*this, index_head.sel == index_component_t::SEL_BIT); - ivl_assert(*this, index_head.msb != 0); - ivl_assert(*this, index_head.lsb == 0); - - if (debug_elaborate) - cerr << get_fileline() << ": debug: elaborate array " - << name_tail.name << " with index " << index_head << endl; - - NetExpr*index_ex = elab_and_eval(des, scope, index_head.msb, -1); - if (index_ex == 0) - return 0; - - if (NetEConst*index_co = dynamic_cast (index_ex)) { - long index = index_co->value().as_long(); - - if (!sig->array_index_is_valid(index)) { - // Oops! The index is a constant known to be - // outside the array. Change the expression to a - // constant X vector. - verinum xxx (verinum::Vx, sig->vector_width()); - NetConst*con_n = new NetConst(scope, scope->local_symbol(), xxx); - des->add_node(con_n); - con_n->set_line(*index_co); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, sig->vector_width()); - tmp->set_line(*this); - tmp->local_flag(true); - tmp->data_type(sig->data_type()); - connect(tmp->pin(0), con_n->pin(0)); - return tmp; - } - - assert(sig->array_index_is_valid(index)); - index = sig->array_index_to_address(index); - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate word " - << index << " of " << sig->name() << endl; - } - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, sig->vector_width()); - tmp->set_line(*this); - tmp->local_flag(true); - tmp->data_type(sig->data_type()); - connect(tmp->pin(0), sig->pin(index)); - - // If there are more indices then needed to get to the - // word, then there is a part/bit select for the word. - if (name_tail.index.size() > sig->array_dimensions()) - tmp = process_select_(des, scope, tmp); - - return tmp; - } - - unsigned selwid = index_ex->expr_width(); - - NetArrayDq*mux = new NetArrayDq(scope, scope->local_symbol(), - sig, selwid); - mux->set_line(*this); - des->add_node(mux); - - // Adjust the expression to calculate the canonical offset? - if (long array_base = sig->array_first()) { - index_ex = make_add_expr(index_ex, 0-array_base); - } - - NetNet*index_net = index_ex->synthesize(des, scope); - connect(mux->pin_Address(), index_net->pin(0)); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, sig->vector_width()); - tmp->set_line(*this); - tmp->local_flag(true); - tmp->data_type(sig->data_type()); - connect(tmp->pin(0), mux->pin_Result()); -#if 0 - - // If there are more index items then there are array - // dimensions, then treat them as word part selects. For - // example, if this is a memory array, then array dimensions - // is 1 and - unsigned midx, lidx; - if (eval_part_select_(des, scope, sig, midx, lidx)) do { - - unsigned part_count = midx-lidx+1; - - // Maybe this is a full-width constant part select? If - // so, do nothing. - if (part_count == sig->vector_width()) - break; - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate part select" - << " of word from " << sig->name() << "[base="<set_line(*sig); - des->add_node(ps); - - NetNet*tmp2 = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, part_count-1, 0); - tmp2->data_type( tmp->data_type() ); - tmp2->local_flag(true); - connect(tmp2->pin(0), ps->pin(0)); - - tmp = tmp2; - } while (0); -#else - if (name_tail.index.size() > sig->array_dimensions()) - tmp = process_select_(des, scope, tmp); - -#endif - return tmp; -} - /* * The concatenation is also OK an an l-value. This method elaborates * it as a structural l-value. The return values is the *input* net of @@ -2468,42 +164,6 @@ NetNet* PEConcat::elaborate_bi_net(Design*des, NetScope*scope) const return elaborate_lnet_common_(des, scope, true); } -/* - * Elaborate a number as a NetConst object. - */ -NetNet* PEFNumber::elaborate_net(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Elaborate real literal node, " - << "value=" << value() << "." << endl; - } - - NetLiteral*obj = new NetLiteral(scope, scope->local_symbol(), value()); - obj->set_line(*this); - obj->rise_time(rise); - obj->fall_time(fall); - obj->decay_time(decay); - obj->pin(0).drive0(drive0); - obj->pin(0).drive1(drive1); - des->add_node(obj); - - NetNet*net = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, 1); - net->data_type(IVL_VT_REAL); - net->set_signed(true); - net->local_flag(true); - net->set_line(*this); - - connect(obj->pin(0), net->pin(0)); - - return net; -} - /* * A private method to create an implicit net. */ @@ -2929,781 +589,3 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const return sig; } -/* - * Elaborate a number as a NetConst object. - * - * The code assumes that the result is IVL_VT_LOGIC. - */ -NetNet* PENumber::elaborate_net(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - NetNet *net; - NetConst *con; - - /* If we are constrained by a l-value size, then just make a - number constant with the correct size and set as many bits - in that constant as make sense. Pad excess with - zeros. Also, assume that numbers are meant to be logic - type. */ - if (lwidth > 0) { - net = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, lwidth); - net->data_type(IVL_VT_LOGIC); - net->local_flag(true); - net->set_signed(value_->has_sign()); - - verinum num = pad_to_width(*value_, lwidth); - if (num.len() > lwidth) - num = verinum(num, lwidth); - - con = new NetConst(scope, scope->local_symbol(), num); - - /* If the number has a length, then use that to size the - number. Generate a constant object of exactly the user - specified size. */ - } else if (value_->has_len()) { - net = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, value_->len()); - net->data_type(IVL_VT_LOGIC); - net->local_flag(true); - net->set_signed(value_->has_sign()); - con = new NetConst(scope, scope->local_symbol(), - *value_); - - /* None of the above tight constraints are present, so make a - plausible choice for the width. Try to reduce the width as - much as possible by eliminating high zeros of unsigned - numbers. */ - } else { - - if (must_be_self_determined_flag) { - cerr << get_fileline() << ": error: No idea how wide to " - << "make the unsized constant " << *value_ << "." << endl; - des->errors += 1; - } - - unsigned width = value_->len(); - - if (value_->has_sign() && (value_->get(width-1) == verinum::V0)) { - - /* If the number is signed, but known to be positive, - then reduce it down as if it were unsigned. */ - while (width > 1) { - if (value_->get(width-1) != verinum::V0) - break; - width -= 1; - - } - - } else if (value_->has_sign() == false) { - while ( (width > 1) && (value_->get(width-1) == verinum::V0)) - width -= 1; - } - - verinum num (verinum::V0, width); - for (unsigned idx = 0 ; idx < width ; idx += 1) - num.set(idx, value_->get(idx)); - - net = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, width); - net->data_type(IVL_VT_LOGIC); - net->local_flag(true); - con = new NetConst(scope, scope->local_symbol(), num); - } - - con->rise_time(rise); - con->fall_time(fall); - con->decay_time(decay); - con->pin(0).drive0(drive0); - con->pin(0).drive1(drive1); - - connect(con->pin(0), net->pin(0)); - - des->add_node(con); - return net; -} - -/* - * A string is a NetEConst node that is made of the ASCII bits of the - * string instead of the bits of a number. In fact, a string is just - * another numeric notation. - */ -NetNet* PEString::elaborate_net(Design*des, NetScope*scope, - unsigned lwidth, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - unsigned strbits = strlen(text_) * 8; - NetNet*net; - - /* If we are constrained by a l-value size, then just make a - number constant with the correct size and set as many bits - in that constant as make sense. Pad excess with zeros. */ - if (lwidth > 0) { - net = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, lwidth); - - } else { - net = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, strbits); - } - net->data_type(IVL_VT_BOOL); - net->local_flag(true); - - /* Make a verinum that is filled with the 0 pad. */ - verinum num(verinum::V0, net->vector_width()); - - unsigned idx; - for (idx = 0 ; idx < num.len() && idx < strbits; idx += 1) { - char byte = text_[strbits/8 - 1 - idx/8]; - char mask = 1<<(idx%8); - num.set(idx, (byte & mask)? verinum::V1 : verinum::V0); - } - - NetConst*con = new NetConst(scope, scope->local_symbol(), num); - con->set_line(*this); - con->rise_time(rise); - con->fall_time(fall); - con->decay_time(decay); - con->pin(0).drive0(drive0); - con->pin(0).drive1(drive1); - - des->add_node(con); - - connect(con->pin(0), net->pin(0)); - - return net; -} - -/* Common processing for the case when a single argument is always - * selected in a ternary operator. */ -static void process_single_ternary(Design*des, const PExpr*base, - unsigned width, NetNet*&sig) -{ - /* We must have a type for the signal. */ - if (sig->data_type() == IVL_VT_NO_TYPE) { - cerr << base->get_fileline() << ": internal error: constant " - << "selected ternary clause has NO TYPE." << endl; - des->errors += 1; - sig = 0; - } - - /* Use the signal width if one is not provided. - * Pad or crop as needed. */ - if (width == 0) width = sig->vector_width(); - - if (sig->vector_width() < width) sig = pad_to_width(des, sig, width); - - if (width < sig->vector_width()) sig = crop_to_width(des, sig, width); - - sig->set_line(*base); -} - -/* - * Elaborate the ternary operator in a netlist by creating a LPM_MUX - * with width matching the result, size == 2 and 1 select input. These - * expressions come from code like: - * - * res = test ? a : b; - * - * The res has the width requested of this method, and the a and b - * expressions have their own similar widths. The test expression is - * only a single bit wide. The output from this function is a NetNet - * object the width of the expression and connected to the - * Result pins of the LPM_MUX device. Any width not covered by the - * width of the mux is padded with a NetConst device. - */ -NetNet* PETernary::elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - NetNet *expr_sig, *tru_sig, *fal_sig; - - NetExpr*expr = elab_and_eval(des, scope, expr_, 0); - if (expr == 0) return 0; - - /* If we have a constant conditional we can avoid some steps. */ - switch (const_logical(expr)) { - case C_0: - fal_sig = fal_->elaborate_net(des, scope, width, 0, 0, 0); - if (fal_sig == 0) return 0; - process_single_ternary(des, this, width, fal_sig); - return fal_sig; - break; - - case C_1: - tru_sig = tru_->elaborate_net(des, scope, width, 0, 0, 0); - if (tru_sig == 0) return 0; - process_single_ternary(des, this, width, tru_sig); - return tru_sig; - break; - - default: - tru_sig = tru_->elaborate_net(des, scope, width, 0, 0, 0); - fal_sig = fal_->elaborate_net(des, scope, width, 0, 0, 0); - /* We should really see if these are constant values and - * mix them as needed so we can omit the MUX? below, but - * since this is a very uncommon case, I'm going to pass - * on this for now. */ - break; - } - expr_sig = expr->synthesize(des, scope); - - if (expr_sig == 0 || tru_sig == 0 || fal_sig == 0) return 0; - - /* The type of the true and false expressions must - match. These become the type of the resulting - expression. */ - - ivl_variable_type_t expr_type = tru_sig->data_type(); - - if (tru_sig->data_type() != fal_sig->data_type()) { - cerr << get_fileline() << ": error: True and False clauses of" - << " ternary expression have different types." << endl; - cerr << get_fileline() << ": : True clause is " - << tru_sig->data_type() << ", false clause is " - << fal_sig->data_type() << "." << endl; - - des->errors += 1; - expr_type = IVL_VT_NO_TYPE; - return 0; - - } else if (expr_type == IVL_VT_NO_TYPE) { - cerr << get_fileline() << ": internal error: True and false " - << "clauses of ternary both have NO TYPE." << endl; - des->errors += 1; - return 0; - } - - /* The natural width of the expression is the width of the - largest condition. Normally they should be the same size, - but if we do not get a size from the context, or the - expressions resist, we need to cope. */ - unsigned iwidth = tru_sig->vector_width(); - if (fal_sig->vector_width() > iwidth) iwidth = fal_sig->vector_width(); - - /* If the width is not passed from the context, then take the - widest result as our width. */ - if (width == 0) width = iwidth; - - /* If the expression has width, then generate a boolean result - by connecting an OR gate to calculate the truth value of - the result. In the end, the result needs to be a single bit. */ - if (expr_sig->vector_width() > 1) { - NetUReduce*log = new NetUReduce(scope, scope->local_symbol(), - NetUReduce::OR, - expr_sig->vector_width()); - log->set_line(*this); - des->add_node(log); - connect(log->pin(1), expr_sig->pin(0)); - - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, 1); - tmp->data_type(IVL_VT_LOGIC); - tmp->local_flag(true); - connect(log->pin(0), tmp->pin(0)); - - expr_sig = tmp; - } - - assert(expr_sig->vector_width() == 1); - - /* This is the width of the LPM_MUX device that I'm about to - create. It may be smaller then the desired output, but I'll - handle padding below. Note that in principle the - alternatives should be padded to the output width first, - but it is more efficient to pad them only just enough to - prevent loss, and do the finished padding later. - - Create a NetNet object wide enough to hold the - result. Also, pad the result values (if necessary) so that - the mux inputs can be fully connected. */ - - unsigned dwidth = (iwidth > width)? width : iwidth; - - NetNet*sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, dwidth); - sig->data_type(expr_type); - sig->local_flag(true); - - if (fal_sig->vector_width() < dwidth) - fal_sig = pad_to_width(des, fal_sig, dwidth); - - if (tru_sig->vector_width() < dwidth) - tru_sig = pad_to_width(des, tru_sig, dwidth); - - if (dwidth < fal_sig->vector_width()) - fal_sig = crop_to_width(des, fal_sig, dwidth); - - if (dwidth < tru_sig->vector_width()) - tru_sig = crop_to_width(des, tru_sig, dwidth); - - /* Make the device and connect its outputs to the osig and - inputs to the tru and false case nets. Also connect the - selector bit to the sel input. - - The inputs are the 0 (false) connected to fal_sig and 1 - (true) connected to tru_sig. */ - - NetMux*mux = new NetMux(scope, scope->local_symbol(), dwidth, 2, 1); - connect(mux->pin_Sel(), expr_sig->pin(0)); - - /* Connect the data inputs. */ - connect(mux->pin_Data(0), fal_sig->pin(0)); - connect(mux->pin_Data(1), tru_sig->pin(0)); - - /* If there are non-zero output delays, then create bufz - devices to carry the propagation delays. Otherwise, just - connect the result to the output. */ - if (rise || fall || decay) { - NetNet*tmp = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, dwidth); - tmp->data_type(expr_type); - tmp->local_flag(true); - - NetBUFZ*tmpz = new NetBUFZ(scope, scope->local_symbol(), dwidth); - tmpz->rise_time(rise); - tmpz->fall_time(fall); - tmpz->decay_time(decay); - tmpz->pin(0).drive0(drive0); - tmpz->pin(0).drive1(drive1); - - connect(mux->pin_Result(), tmp->pin(0)); - connect(tmp->pin(0), tmpz->pin(1)); - connect(sig->pin(0), tmpz->pin(0)); - - des->add_node(tmpz); - } else { - connect(mux->pin_Result(), sig->pin(0)); - } - - /* If the MUX device result is too narrow to fill out the - desired result, pad with zeros... */ - assert(dwidth <= width); - - des->add_node(mux); - - /* If the MUX device results is too narrow to fill out the - desired result, then pad it. It is OK to have a too-narrow - result here because the dwidth choice is >= the width of - both alternatives. Thus, padding here is equivalent to - padding inside, and is cheaper. */ - if (dwidth < width) - sig = pad_to_width(des, sig, width); - - return sig; -} - -NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - // Some unary operands allow the operand to be - // self-determined, and some do not. - unsigned owidth = 0; - switch (op_) { - case '~': - case '-': - owidth = width; - break; - } - - NetExpr*expr = elab_and_eval(des, scope, expr_, owidth); - if (expr == 0) return 0; - - NetNet* sig = 0; - NetLogic*gate; - - - // Handle the special case of a 2's complement of a constant - // value. This can be reduced to a no-op on a precalculated - // result. - if (op_ == '-') { - if (NetEConst*tmp = dynamic_cast(expr)) { - return elab_net_uminus_const_logic_(des, scope, tmp, - width, rise, fall, decay, - drive0, drive1); - } - - if (NetECReal*tmp = dynamic_cast(expr)) { - return elab_net_uminus_const_real_(des, scope, tmp, - width, rise, fall, decay, - drive0, drive1); - } - } - - // Handle the case that the expression is real-valued. - if (expr->expr_type() == IVL_VT_REAL) { - return elab_net_unary_real_(des, scope, expr, - width, rise, fall, decay, - drive0, drive1); - } - - NetNet* sub_sig = expr->synthesize(des, scope); - - if (sub_sig == 0) return 0; - - delete expr; - expr = 0; - - bool reduction=false; - NetUReduce::TYPE rtype = NetUReduce::NONE; - - switch (op_) { - case '~': // Bitwise NOT - sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, - sub_sig->vector_width()); - sig->data_type(sub_sig->data_type()); - sig->local_flag(true); - gate = new NetLogic(scope, scope->local_symbol(), - 2, NetLogic::NOT, sub_sig->vector_width()); - gate->set_line(*this); - des->add_node(gate); - gate->rise_time(rise); - gate->fall_time(fall); - gate->decay_time(decay); - - connect(gate->pin(1), sub_sig->pin(0)); - connect(gate->pin(0), sig->pin(0)); - break; - - case 'm': // abs(sub_sig) - // If this expression is self determined, get its width - // from the sub_expression. - if (owidth == 0) - owidth = sub_sig->vector_width(); - - if (sub_sig->vector_width() < owidth) - sub_sig = pad_to_width(des, sub_sig, owidth); - - sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, owidth); - sig->set_line(*this); - sig->data_type(sub_sig->data_type()); - sig->local_flag(true); - - { NetAbs*tmp = new NetAbs(scope, scope->local_symbol(), sub_sig->vector_width()); - tmp->set_line(*this); - des->add_node(tmp); - tmp->rise_time(rise); - tmp->fall_time(fall); - tmp->decay_time(decay); - - connect(tmp->pin(1), sub_sig->pin(0)); - connect(tmp->pin(0), sig->pin(0)); - } - break; - - case 'N': // Reduction NOR - case '!': // Reduction NOT - reduction=true; rtype = NetUReduce::NOR; break; - case '&': // Reduction AND - reduction=true; rtype = NetUReduce::AND; break; - case '|': // Reduction OR - reduction=true; rtype = NetUReduce::OR; break; - case '^': // Reduction XOR - reduction=true; rtype = NetUReduce::XOR; break; - case 'A': // Reduction NAND (~&) - reduction=true; rtype = NetUReduce::NAND; break; - case 'X': // Reduction XNOR (~^) - reduction=true; rtype = NetUReduce::XNOR; break; - - case '-': // Unary 2's complement. - // If this expression is self determined, get its width - // from the sub_expression. - if (owidth == 0) - owidth = sub_sig->vector_width(); - - sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, owidth); - sig->data_type(sub_sig->data_type()); - sig->local_flag(true); - - if (sub_sig->vector_width() < owidth) - sub_sig = pad_to_width(des, sub_sig, owidth); - - switch (sub_sig->vector_width()) { - case 0: - assert(0); - break; - - case 1: - gate = new NetLogic(scope, scope->local_symbol(), - 2, NetLogic::BUF, 1); - connect(gate->pin(0), sig->pin(0)); - connect(gate->pin(1), sub_sig->pin(0)); - des->add_node(gate); - gate->set_line(*this); - gate->rise_time(rise); - gate->fall_time(fall); - gate->decay_time(decay); - break; - - default: - NetAddSub*sub = new NetAddSub(scope, scope->local_symbol(), - sig->vector_width()); - sub->attribute(perm_string::literal("LPM_Direction"), - verinum("SUB")); - sub->set_line(*this); - sub->rise_time(rise); - sub->fall_time(fall); - sub->decay_time(decay); - des->add_node(sub); - - connect(sig->pin(0), sub->pin_Result()); - connect(sub_sig->pin(0), sub->pin_DataB()); - - verinum tmp_num (verinum::V0, sub->width(), true); - NetConst*tmp_con = new NetConst(scope, - scope->local_symbol(), - tmp_num); - des->add_node(tmp_con); - - NetNet*tmp_sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, - sub_sig->vector_width()); - tmp_sig->data_type(sub_sig->data_type()); - tmp_sig->local_flag(true); - - connect(tmp_sig->pin(0), sub->pin_DataA()); - connect(tmp_sig->pin(0), tmp_con->pin(0)); - break; - } - break; - - default: - cerr << get_fileline() << ": internal error: Unhandled UNARY '" << op_ << "'" << endl; - sig = 0; - } - - if (reduction) { - NetUReduce*rgate; - - // The output of a reduction operator is 1 bit - sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE, 1); - sig->data_type(sub_sig->data_type()); - sig->local_flag(true); - - rgate = new NetUReduce(scope, scope->local_symbol(), - rtype, sub_sig->vector_width()); - rgate->set_line(*this); - connect(rgate->pin(0), sig->pin(0)); - connect(rgate->pin(1), sub_sig->pin(0)); - - des->add_node(rgate); - rgate->rise_time(rise); - rgate->fall_time(fall); - rgate->decay_time(decay); - } - - return sig; -} - -NetNet* PEUnary::elab_net_uminus_const_logic_(Design*des, NetScope*scope, - NetEConst*expr, - unsigned width, - const NetExpr* rise, - const NetExpr* fall, - const NetExpr* decay, - Link::strength_t drive0, - Link::strength_t drive1) const -{ - verinum val = expr->value(); - - if (width == 0) - width = val.len(); - - assert(width > 0); - NetNet*sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, width); - sig->data_type(IVL_VT_LOGIC); - sig->local_flag(true); - sig->set_line(*this); - - /* Take the 2s complement by taking the 1s complement - and adding 1. */ - verinum tmp (v_not(val), width); - verinum one (1UL, width); - tmp = verinum(tmp + one, width); - tmp.has_sign(val.has_sign()); - - NetConst*con = new NetConst(scope, scope->local_symbol(), tmp); - - connect(con->pin(0), sig->pin(0)); - - con->set_line(*this); - con->rise_time(rise); - con->fall_time(fall); - con->decay_time(decay); - con->pin(0).drive0(drive0); - con->pin(0).drive1(drive1); - - des->add_node(con); - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Replace expression " - << *this << " with constant " << tmp << "."<value(); - - NetNet*sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, width); - sig->data_type(IVL_VT_REAL); - sig->set_signed(true); - sig->local_flag(true); - sig->set_line(*this); - - NetLiteral*con = new NetLiteral(scope, scope->local_symbol(), -val); - - connect(con->pin(0), sig->pin(0)); - - con->set_line(*this); - con->rise_time(rise); - con->fall_time(fall); - con->decay_time(decay); - con->pin(0).drive0(drive0); - con->pin(0).drive1(drive1); - - des->add_node(con); - - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Replace expression " - << *this << " with constant " << con->value_real() << "."<synthesize(des, scope); - - if (sub_sig == 0) return 0; - delete expr; - - NetNet*sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, 1); - sig->data_type(IVL_VT_REAL); - sig->set_signed(true); - sig->local_flag(true); - sig->set_line(*this); - - switch (op_) { - - default: - cerr << get_fileline() << ": internal error: Unhandled UNARY " - << op_ << " expression with real values." << endl; - des->errors += 1; - break; - case '~': - cerr << get_fileline() << ": error: bit-wise negation (" - << human_readable_op(op_) - << ") may not have a REAL operand." << endl; - des->errors += 1; - break; - case '&': - case 'A': - case '|': - case 'N': - case '^': - case 'X': - cerr << get_fileline() << ": error: reduction operator (" - << human_readable_op(op_) - << ") may not have a REAL operand." << endl; - des->errors += 1; - break; - case '!': - cerr << get_fileline() << ": sorry: ! is currently unsupported" - " for real values." << endl; - des->errors += 1; - break; - - case 'm': { // abs() - NetAbs*tmp = new NetAbs(scope, scope->local_symbol(), 1); - tmp->set_line(*this); - tmp->rise_time(rise); - tmp->fall_time(fall); - tmp->decay_time(decay); - des->add_node(tmp); - - connect(tmp->pin(0), sig->pin(0)); - connect(tmp->pin(1), sub_sig->pin(0)); - break; - } - - case '-': - NetAddSub*sub = new NetAddSub(scope, scope->local_symbol(), 1); - sub->attribute(perm_string::literal("LPM_Direction"), - verinum("SUB")); - sub->set_line(*this); - sub->rise_time(rise); - sub->fall_time(fall); - sub->decay_time(decay); - des->add_node(sub); - connect(sig->pin(0), sub->pin_Result()); - connect(sub_sig->pin(0), sub->pin_DataB()); - - NetLiteral*tmp_con = new NetLiteral(scope, scope->local_symbol(), - verireal(0.0)); - tmp_con->set_line(*this); - des->add_node(tmp_con); - - NetNet*tmp_sig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, 1); - tmp_sig->data_type(IVL_VT_REAL); - tmp_sig->set_signed(true); - tmp_sig->local_flag(true); - tmp_sig->set_line(*this); - - connect(tmp_sig->pin(0), sub->pin_DataA()); - connect(tmp_sig->pin(0), tmp_con->pin(0)); - break; - } - - return sig; -} From 8704e3e34fc8b7d46b0161ab7e782acc20660f83 Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Tue, 9 Sep 2008 09:27:04 -0700 Subject: [PATCH 32/93] Compatibility with gcc-4.3 Add "include"s to fix errors flagged by gcc-4.3.2 --- elab_expr.cc | 1 + expr_synth.cc | 1 + tgt-null/null.c | 1 + 3 files changed, 3 insertions(+) diff --git a/elab_expr.cc b/elab_expr.cc index e345d3ea4..11ac12dcc 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -21,6 +21,7 @@ # include # include # include +# include # include "compiler.h" # include "pform.h" diff --git a/expr_synth.cc b/expr_synth.cc index 49ab9b306..d323b7dd3 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -20,6 +20,7 @@ # include "config.h" # include "compiler.h" +# include # include # include "netlist.h" diff --git a/tgt-null/null.c b/tgt-null/null.c index 516c3cd37..9bed4a68d 100644 --- a/tgt-null/null.c +++ b/tgt-null/null.c @@ -18,6 +18,7 @@ */ # include "config.h" +# include /* * This is a null target module. It does nothing. From f233793061c3f578501181940a6c3fba5a0a4942 Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Tue, 9 Sep 2008 09:30:47 -0700 Subject: [PATCH 33/93] Spelling fixes No code changes. --- driver/main.c | 2 +- pform_disciplines.cc | 2 +- tgt-vhdl/logic.cc | 2 +- tgt-vhdl/stmt.cc | 8 ++++---- tgt-vhdl/vhdl.cc | 2 +- tgt-vhdl/vhdl_syntax.cc | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/driver/main.c b/driver/main.c index d0f1c387b..89eb919a7 100644 --- a/driver/main.c +++ b/driver/main.c @@ -929,7 +929,7 @@ int main(int argc, char **argv) /* Done writing to the iconfig file. Close it now. */ fclose(iconfig_file); - /* If we're only here for th verion output, then we're done. */ + /* If we're only here for the version output, then we're done. */ if (version_flag) return t_version_only(); diff --git a/pform_disciplines.cc b/pform_disciplines.cc index 2ce7aeedd..5660a8fe5 100644 --- a/pform_disciplines.cc +++ b/pform_disciplines.cc @@ -78,7 +78,7 @@ void pform_end_nature(const struct vlltype&loc) error_count += 1; } - // Map the access functio back to the nature so that + // Map the access function back to the nature so that // expressions that use the access function can find it. access_function_nature[nature_access] = tmp; diff --git a/tgt-vhdl/logic.cc b/tgt-vhdl/logic.cc index 80e5fe28e..269497b0d 100644 --- a/tgt-vhdl/logic.cc +++ b/tgt-vhdl/logic.cc @@ -47,7 +47,7 @@ static vhdl_expr *inputs_to_expr(vhdl_scope *scope, vhdl_binop_t op, } /* - * Convert a gate intput to an unary expression. + * Convert a gate input to an unary expression. */ static vhdl_expr *input_to_expr(vhdl_scope *scope, vhdl_unaryop_t op, ivl_net_logic_t log) diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index f1a5eb9c7..b3c18bfbd 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -34,7 +34,7 @@ * successfully. * * An alternative is to use the VHPI interface supported by - * some VHDL simulators and implement the $finish funcitonality + * some VHDL simulators and implement the $finish functionality * in C. This function can be enabled with the flag * -puse-vhpi-finish=1. */ @@ -226,12 +226,12 @@ void make_assignment(vhdl_procedural *proc, stmt_container *container, // performed on assignments of constant values to prevent // ordering problems. - // This also has another application: If this is an `inital' + // This also has another application: If this is an `initial' // process and we haven't yet generated a `wait' statement then // moving the assignment to the initialization preserves the // expected Verilog behaviour: VHDL does not distinguish // `initial' and `always' processes so an `always' process might - // be activatated before an `initial' process at time 0. The + // be activated before an `initial' process at time 0. The // `always' process may then use the uninitialized signal value. // The second test ensures that we only try to initialise // internal signals not ports @@ -622,7 +622,7 @@ int draw_utask(vhdl_procedural *proc, stmt_container *container, // TODO: adding some comments to the output would be helpful - // TOOD: this completely ignores paremeters! + // TOOD: this completely ignores parameters! draw_stmt(proc, container, ivl_scope_def(tscope), false); return 0; diff --git a/tgt-vhdl/vhdl.cc b/tgt-vhdl/vhdl.cc index a82f583d3..46c734422 100644 --- a/tgt-vhdl/vhdl.cc +++ b/tgt-vhdl/vhdl.cc @@ -97,7 +97,7 @@ bool seen_signal_before(ivl_signal_t sig) } /* - * Remeber the association of signal to entity. + * Remember the association of signal to entity. */ void remember_signal(ivl_signal_t sig, vhdl_scope *scope) { diff --git a/tgt-vhdl/vhdl_syntax.cc b/tgt-vhdl/vhdl_syntax.cc index 2de81f1c6..1f3139564 100644 --- a/tgt-vhdl/vhdl_syntax.cc +++ b/tgt-vhdl/vhdl_syntax.cc @@ -854,7 +854,7 @@ vhdl_function::vhdl_function(const char *name, vhdl_type *ret_type) : vhdl_decl(name, ret_type) { // A function contains two scopes: - // scope_ = The paramters + // scope_ = The parameters // variables_ = Local variables // A call to get_scope returns variables_ whose parent is scope_ variables_.set_parent(&scope_); From 3982781e973f57e3404aeaf4e3fe3f375b0be3e5 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 9 Sep 2008 13:48:54 -0700 Subject: [PATCH 34/93] Add cast to remove warning. --- elaborate.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elaborate.cc b/elaborate.cc index 14cdd478c..63240538d 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -110,7 +110,7 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const << ", unsized_flag=" << (unsized_flag?"true":"false") << endl; } - int expr_wid = unsized_flag? -1 : use_width; + int expr_wid = unsized_flag? -1 : (int) use_width; NetExpr*rval_expr = elab_and_eval(des, scope, pin(1), expr_wid, lval->vector_width()); From 088c7f3febc265c6860767cd94df6c709d50e8ae Mon Sep 17 00:00:00 2001 From: Cary R Date: Mon, 8 Sep 2008 19:49:52 -0700 Subject: [PATCH 35/93] Add calculated delay, real valued, non-blocking assignments. This patch add the ability to do a non-blocking assignment for real values using a non-constant (calculated) delay. --- tgt-vvp/vvp_process.c | 19 ++++++++++++------- vvp/codes.h | 1 + vvp/compile.cc | 1 + vvp/opcodes.txt | 11 ++++++++--- vvp/vthread.cc | 19 +++++++++++++++++++ 5 files changed, 41 insertions(+), 10 deletions(-) diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 6147b5225..861ce2232 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -531,7 +531,7 @@ static int show_stmt_assign_nb_real(ivl_statement_t net) unsigned long use_word = 0; /* thread address for a word value. */ int word; - unsigned long delay; + unsigned long delay = 0; /* Must be exactly 1 l-value. */ assert(ivl_stmt_lvals(net) == 1); @@ -547,20 +547,25 @@ static int show_stmt_assign_nb_real(ivl_statement_t net) use_word = get_number_immediate(word_ix); } - delay = 0; if (del && (ivl_expr_type(del) == IVL_EX_ULONG)) { delay = ivl_expr_uvalue(del); del = 0; } - /* XXXX For now, presume delays are constant. */ - assert(del == 0); - /* Evaluate the r-value */ word = draw_eval_real(rval); - fprintf(vvp_out, " %%assign/wr v%p_%lu, %lu, %u;\n", - sig, use_word, delay, word); + /* We need to calculate the delay expression. */ + if (del) { + int delay_index = allocate_word(); + draw_eval_expr_into_integer(del, delay_index); + fprintf(vvp_out, " %%assign/wr/d v%p_%lu, %d, %u;\n", + sig, use_word, delay_index, word); + clr_word(delay_index); + } else { + fprintf(vvp_out, " %%assign/wr v%p_%lu, %lu, %u;\n", + sig, use_word, delay, word); + } clr_word(word); diff --git a/vvp/codes.h b/vvp/codes.h index 6fe3f2489..3a803b5e6 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -48,6 +48,7 @@ extern bool of_ASSIGN_V0D(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_V0X1(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_V0X1D(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_WR(vthread_t thr, vvp_code_t code); +extern bool of_ASSIGN_WRD(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_X0(vthread_t thr, vvp_code_t code); extern bool of_BLEND(vthread_t thr, vvp_code_t code); extern bool of_BLEND_WR(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index 09cdbaeee..bdf8d9262 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -93,6 +93,7 @@ const static struct opcode_table_s opcode_table[] = { { "%assign/v0/x1",of_ASSIGN_V0X1,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, { "%assign/v0/x1/d",of_ASSIGN_V0X1D,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, { "%assign/wr",of_ASSIGN_WR,3,{OA_VPI_PTR,OA_BIT1, OA_BIT2} }, + { "%assign/wr/d",of_ASSIGN_WRD,3,{OA_VPI_PTR,OA_BIT1, OA_BIT2} }, { "%assign/x0",of_ASSIGN_X0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} }, { "%blend", of_BLEND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%blend/wr", of_BLEND_WR,2, {OA_BIT1, OA_BIT2, OA_NONE} }, diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index 56652e713..556c0cb27 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -89,7 +89,7 @@ where the assignment should be schedule, and the is the base of the vector to be assigned to the destination. The vector width is in index register 0. -The %assign/v0/d variation puts the delay instead into an integer +The %assign/v0/d variation gets the delay instead from an integer register that is given by the value. This should not be 0, of course, because integer 0 is taken with the vector width. @@ -104,9 +104,14 @@ index register with the canonical index of the destination where the vector is to be written. This allows for part writes into the vector. * %assign/wr , , +* %assign/wr/d , , -This instruction causes a non-blocking assign of the indexed value to -the real object addressed by the label. +This instruction provides a non-blocking assign of the real value +given in to the real object addressed by the +label after the given . + +The %assign/wr/d variation gets the delay from integer register +. * %assign/x0 , , (OBSOLETE -- See %assign/v0x) diff --git a/vvp/vthread.cc b/vvp/vthread.cc index f467bf468..d2fbb9650 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -820,6 +820,25 @@ bool of_ASSIGN_WR(vthread_t thr, vvp_code_t cp) return true; } +bool of_ASSIGN_WRD(vthread_t thr, vvp_code_t cp) +{ + unsigned delay = thr->words[cp->bit_idx[0]].w_int; + unsigned index = cp->bit_idx[1]; + s_vpi_time del; + + del.type = vpiSimTime; + vpip_time_to_timestruct(&del, delay); + + struct __vpiHandle*tmp = cp->handle; + + t_vpi_value val; + val.format = vpiRealVal; + val.value.real = thr->words[index].w_real; + vpi_put_value(tmp, &val, &del, vpiInertialDelay); + + return true; +} + bool of_ASSIGN_X0(vthread_t thr, vvp_code_t cp) { #if 0 From 5dfecb3789c1ea890d1c4221ca88f6612f90bcf5 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 10 Sep 2008 07:29:23 -0700 Subject: [PATCH 36/93] Remove useless Link instance number. --- design_dump.cc | 3 +- net_event.cc | 2 +- net_func.cc | 8 +-- net_link.cc | 12 ++--- net_modulo.cc | 6 +-- net_tran.cc | 10 ++-- net_udp.cc | 4 +- netlist.cc | 136 ++++++++++++++++++++++++------------------------- netlist.h | 4 +- 9 files changed, 88 insertions(+), 97 deletions(-) diff --git a/design_dump.cc b/design_dump.cc index f17ee9605..ad1c89af8 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -244,8 +244,7 @@ void NetNode::dump_node(ostream&o, unsigned ind) const void NetPins::dump_node_pins(ostream&o, unsigned ind) const { for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { - o << setw(ind) << "" << idx << " " << pin(idx).get_name() - << "<" << pin(idx).get_inst() << ">"; + o << setw(ind) << "" << idx << " " << pin(idx).get_name(); switch (pin(idx).get_dir()) { case Link::PASSIVE: diff --git a/net_event.cc b/net_event.cc index 3535e7ea9..529eaf45a 100644 --- a/net_event.cc +++ b/net_event.cc @@ -251,7 +251,7 @@ NetEvProbe::NetEvProbe(NetScope*s, perm_string n, NetEvent*tgt, { for (unsigned idx = 0 ; idx < p ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).set_name(perm_string::literal("P"), idx); + pin(idx).set_name(perm_string::literal("P")); } enext_ = event_->probes_; diff --git a/net_func.cc b/net_func.cc index 564d16258..f3037aa0a 100644 --- a/net_func.cc +++ b/net_func.cc @@ -34,12 +34,12 @@ NetUserFunc::NetUserFunc(NetScope*s, perm_string n, NetScope*d) def_(d) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(def_->basename(), 0); + pin(0).set_name(def_->basename()); for (unsigned idx = 1 ; idx < pin_count() ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).set_name(perm_string::literal("D"), idx-1); + pin(idx).set_name(perm_string::literal("D")); pin(idx).drive0(Link::HIGHZ); pin(idx).drive1(Link::HIGHZ); } @@ -136,12 +136,12 @@ NetSysFunc::NetSysFunc(NetScope*s, perm_string n, def_ = def; pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Q"), 0); + pin(0).set_name(perm_string::literal("Q")); for (unsigned idx = 1 ; idx < pin_count() ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).set_name(perm_string::literal("D"), idx-1); + pin(idx).set_name(perm_string::literal("D")); pin(idx).drive0(Link::HIGHZ); pin(idx).drive1(Link::HIGHZ); } diff --git a/net_link.cc b/net_link.cc index 54271616b..f3e1709ea 100644 --- a/net_link.cc +++ b/net_link.cc @@ -64,7 +64,7 @@ void connect(Link&l, Link&r) Link::Link() : dir_(PASSIVE), drive0_(STRONG), drive1_(STRONG), init_(verinum::Vx), - inst_(0), next_(0), nexus_(0) + next_(0), nexus_(0) { (new Nexus()) -> relink(this); } @@ -206,10 +206,9 @@ unsigned Link::get_pin() const return pin_; } -void Link::set_name(perm_string n, unsigned i) +void Link::set_name(perm_string n) { name_ = n; - inst_ = i; } perm_string Link::get_name() const @@ -217,11 +216,6 @@ perm_string Link::get_name() const return name_; } -unsigned Link::get_inst() const -{ - return inst_; -} - Nexus::Nexus() { name_ = 0; @@ -455,7 +449,7 @@ const char* Nexus::name() const pin = lnk->get_pin(); cerr << "internal error: No signal for nexus of " << obj->name() << " pin " << pin << "(" << - lnk->get_name() << "<" << lnk->get_inst() << ">)" + lnk->get_name() << ")" " type=" << typeid(*obj).name() << "?" << endl; } diff --git a/net_modulo.cc b/net_modulo.cc index 5ff3be9e4..d36571b12 100644 --- a/net_modulo.cc +++ b/net_modulo.cc @@ -41,11 +41,11 @@ NetModulo::NetModulo(NetScope*s, perm_string n, unsigned wr, width_r_(wr), width_a_(wa), width_b_(wb) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result"), 0); + pin(0).set_name(perm_string::literal("Result")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("DataA"), 0); + pin(1).set_name(perm_string::literal("DataA")); pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("DataB"), 0); + pin(2).set_name(perm_string::literal("DataB")); } NetModulo::~NetModulo() diff --git a/net_tran.cc b/net_tran.cc index 42b726307..e07c8a1da 100644 --- a/net_tran.cc +++ b/net_tran.cc @@ -45,19 +45,19 @@ static bool has_enable(ivl_switch_type_t tt) NetTran::NetTran(NetScope*scope, perm_string n, ivl_switch_type_t tt) : NetNode(scope, n, has_enable(tt)? 3 : 2), type_(tt) { - pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A"), 0); - pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B"), 0); + pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A")); + pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B")); if (pin_count() == 3) { pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("E"), 0); + pin(2).set_name(perm_string::literal("E")); } } NetTran::NetTran(NetScope*scope, perm_string n, unsigned wid, unsigned part, unsigned off) : NetNode(scope, n, 2), type_(IVL_SW_TRAN_VP), wid_(wid), part_(part), off_(off) { - pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A"), 0); - pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B"), 0); + pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A")); + pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B")); } NetTran::~NetTran() diff --git a/net_udp.cc b/net_udp.cc index c5d3df01f..b371d4195 100644 --- a/net_udp.cc +++ b/net_udp.cc @@ -30,10 +30,10 @@ NetUDP::NetUDP(NetScope*s, perm_string n, unsigned pins, PUdp *u) : NetNode(s, n, pins), udp(u) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O"), 0); + pin(0).set_name(perm_string::literal("O")); for (unsigned idx = 1 ; idx < pins ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).set_name(perm_string::literal("I"), idx-1); + pin(idx).set_name(perm_string::literal("I")); } } diff --git a/netlist.cc b/netlist.cc index abe72999b..a1f22daa0 100644 --- a/netlist.cc +++ b/netlist.cc @@ -238,9 +238,9 @@ NetNode::~NetNode() NetBranch::NetBranch(discipline_t*dis) : NetPins(2), discipline_(dis) { - pin(0).set_name(perm_string::literal("A"), 0); + pin(0).set_name(perm_string::literal("A")); pin(0).set_dir(Link::PASSIVE); - pin(1).set_name(perm_string::literal("B"), 0); + pin(1).set_name(perm_string::literal("B")); pin(1).set_dir(Link::PASSIVE); } @@ -266,13 +266,13 @@ NetDelaySrc::NetDelaySrc(NetScope*s, perm_string n, unsigned npins, posedge_ = false; negedge_ = false; for (unsigned idx = 0 ; idx < npins ; idx += 1) { - pin(idx).set_name(perm_string::literal("I"), idx); + pin(idx).set_name(perm_string::literal("I")); pin(idx).set_dir(Link::INPUT); } if (condit_src) { condit_flag_ = true; - pin(npins).set_name(perm_string::literal("COND"), 0); + pin(npins).set_name(perm_string::literal("COND")); pin(npins).set_dir(Link::INPUT); } } @@ -455,7 +455,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins) break; } - pin(0).set_name(perm_string::literal("P"), 0); + pin(0).set_name(perm_string::literal("P")); pin(0).set_dir(dir); pin(0).set_init(init_value); @@ -494,7 +494,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, } for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { - pin(idx).set_name(perm_string::literal("P"), idx); + pin(idx).set_name(perm_string::literal("P")); pin(idx).set_dir(dir); pin(idx).set_init(init_value); } @@ -542,7 +542,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, } for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { - pin(idx).set_name(perm_string::literal("P"), idx); + pin(idx).set_name(perm_string::literal("P")); pin(idx).set_dir(dir); pin(idx).set_init(init_value); } @@ -799,8 +799,8 @@ NetPartSelect::NetPartSelect(NetNet*sig, unsigned off, unsigned wid, pin(1).set_dir(Link::OUTPUT); break; } - pin(0).set_name(perm_string::literal("Part"), 0); - pin(1).set_name(perm_string::literal("Vect"), 0); + pin(0).set_name(perm_string::literal("Part")); + pin(1).set_name(perm_string::literal("Vect")); } NetPartSelect::NetPartSelect(NetNet*sig, NetNet*sel, @@ -823,9 +823,9 @@ NetPartSelect::NetPartSelect(NetNet*sig, NetNet*sel, } pin(2).set_dir(Link::INPUT); - pin(0).set_name(perm_string::literal("Part"), 0); - pin(1).set_name(perm_string::literal("Vect"), 0); - pin(2).set_name(perm_string::literal("Select"), 0); + pin(0).set_name(perm_string::literal("Part")); + pin(1).set_name(perm_string::literal("Vect")); + pin(2).set_name(perm_string::literal("Select")); } NetPartSelect::~NetPartSelect() @@ -890,28 +890,28 @@ NetCastInt::NetCastInt(NetScope*scope, perm_string n, unsigned width) : NetNode(scope, n, 2), width_(width) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O"), 0); + pin(0).set_name(perm_string::literal("O")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("I"), 0); + pin(1).set_name(perm_string::literal("I")); } NetCastReal::NetCastReal(NetScope*scope, perm_string n, bool signed_flag) : NetNode(scope, n, 2), signed_flag_(signed_flag) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O"), 0); + pin(0).set_name(perm_string::literal("O")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("I"), 0); + pin(1).set_name(perm_string::literal("I")); } NetConcat::NetConcat(NetScope*scope, perm_string n, unsigned wid, unsigned cnt) : NetNode(scope, n, cnt+1), width_(wid) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O"), 0); + pin(0).set_name(perm_string::literal("O")); for (unsigned idx = 1 ; idx < cnt+1 ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).set_name(perm_string::literal("I"), idx-1); + pin(idx).set_name(perm_string::literal("I")); } } @@ -929,9 +929,9 @@ NetReplicate::NetReplicate(NetScope*scope, perm_string n, : NetNode(scope, n, 2), width_(wid), repeat_(rpt) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O"), 0); + pin(0).set_name(perm_string::literal("O")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("I"), 0); + pin(1).set_name(perm_string::literal("I")); } NetReplicate::~NetReplicate() @@ -966,21 +966,21 @@ NetFF::NetFF(NetScope*s, perm_string n, unsigned width) : NetNode(s, n, 8), width_(width) { pin_Clock().set_dir(Link::INPUT); - pin_Clock().set_name(perm_string::literal("Clock"), 0); + pin_Clock().set_name(perm_string::literal("Clock")); pin_Enable().set_dir(Link::INPUT); - pin_Enable().set_name(perm_string::literal("Enable"), 0); + pin_Enable().set_name(perm_string::literal("Enable")); pin_Aset().set_dir(Link::INPUT); - pin_Aset().set_name(perm_string::literal("Aset"), 0); + pin_Aset().set_name(perm_string::literal("Aset")); pin_Aclr().set_dir(Link::INPUT); - pin_Aclr().set_name(perm_string::literal("Aclr"), 0); + pin_Aclr().set_name(perm_string::literal("Aclr")); pin_Sset().set_dir(Link::INPUT); - pin_Sset().set_name(perm_string::literal("Sset"), 0); + pin_Sset().set_name(perm_string::literal("Sset")); pin_Sclr().set_dir(Link::INPUT); - pin_Sclr().set_name(perm_string::literal("Sclr"), 0); + pin_Sclr().set_name(perm_string::literal("Sclr")); pin_Data().set_dir(Link::INPUT); - pin_Data().set_name(perm_string::literal("Data"), 0); + pin_Data().set_name(perm_string::literal("Data")); pin_Q().set_dir(Link::OUTPUT); - pin_Q().set_name(perm_string::literal("Q"), 0); + pin_Q().set_name(perm_string::literal("Q")); } NetFF::~NetFF() @@ -1097,9 +1097,9 @@ NetAbs::NetAbs(NetScope*s, perm_string n, unsigned w) : NetNode(s, n, 2), width_(w) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result"), 0); + pin(0).set_name(perm_string::literal("Result")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("DataA"), 0); + pin(1).set_name(perm_string::literal("DataA")); } NetAbs::~NetAbs() @@ -1128,23 +1128,23 @@ NetAddSub::NetAddSub(NetScope*s, perm_string n, unsigned w) : NetNode(s, n, 9), width_(w) { pin(0).set_dir(Link::INPUT); - pin(0).set_name(perm_string::literal("Add_Sub"), 0); + pin(0).set_name(perm_string::literal("Add_Sub")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("Aclr"), 0); + pin(1).set_name(perm_string::literal("Aclr")); pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("Clock"), 0); + pin(2).set_name(perm_string::literal("Clock")); pin(3).set_dir(Link::INPUT); - pin(3).set_name(perm_string::literal("Cin"), 0); + pin(3).set_name(perm_string::literal("Cin")); pin(4).set_dir(Link::OUTPUT); - pin(4).set_name(perm_string::literal("Cout"), 0); + pin(4).set_name(perm_string::literal("Cout")); pin(5).set_dir(Link::OUTPUT); - pin(5).set_name(perm_string::literal("Overflow"), 0); + pin(5).set_name(perm_string::literal("Overflow")); pin(6).set_dir(Link::INPUT); - pin(6).set_name(perm_string::literal("DataA"), 0); + pin(6).set_name(perm_string::literal("DataA")); pin(7).set_dir(Link::INPUT); - pin(7).set_name(perm_string::literal("DataB"), 0); + pin(7).set_name(perm_string::literal("DataB")); pin(8).set_dir(Link::OUTPUT); - pin(8).set_name(perm_string::literal("Result"), 0); + pin(8).set_name(perm_string::literal("Result")); } NetAddSub::~NetAddSub() @@ -1201,9 +1201,9 @@ NetArrayDq::NetArrayDq(NetScope*s, perm_string n, NetNet*mem, unsigned awid) mem_(mem), awidth_(awid) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result"), 0); + pin(0).set_name(perm_string::literal("Result")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("Address"), 0); + pin(1).set_name(perm_string::literal("Address")); // Increment the expression reference count for the target // memory so that it is not deleted underneath me. mem->incr_eref(); @@ -1262,11 +1262,11 @@ NetCLShift::NetCLShift(NetScope*s, perm_string n, right_flag_(right_flag), signed_flag_(signed_flag) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result"), 0); + pin(0).set_name(perm_string::literal("Result")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("Data"), 0); + pin(1).set_name(perm_string::literal("Data")); pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("Distance"), 0); + pin(2).set_name(perm_string::literal("Distance")); } NetCLShift::~NetCLShift() @@ -1474,11 +1474,11 @@ NetDivide::NetDivide(NetScope*sc, perm_string n, unsigned wr, width_r_(wr), width_a_(wa), width_b_(wb), signed_flag_(false) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result"), 0); + pin(0).set_name(perm_string::literal("Result")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("DataA"), 0); + pin(1).set_name(perm_string::literal("DataA")); pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("DataB"), 0); + pin(2).set_name(perm_string::literal("DataB")); } NetDivide::~NetDivide() @@ -1544,7 +1544,7 @@ NetLiteral::NetLiteral(NetScope*sc, perm_string n, const verireal&val) : NetNode(sc, n, 1), real_(val) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O"), 0); + pin(0).set_name(perm_string::literal("O")); } NetLiteral::~NetLiteral() @@ -1567,11 +1567,11 @@ NetMult::NetMult(NetScope*sc, perm_string n, unsigned wr, signed_(false), width_r_(wr), width_a_(wa), width_b_(wb) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result"), 0); + pin(0).set_name(perm_string::literal("Result")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("DataA"), 0); + pin(1).set_name(perm_string::literal("DataA")); pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("DataB"), 0); + pin(2).set_name(perm_string::literal("DataB")); } NetMult::~NetMult() @@ -1639,11 +1639,11 @@ NetPow::NetPow(NetScope*sc, perm_string n, unsigned wr, signed_(false), width_r_(wr), width_a_(wa), width_b_(wb) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result"), 0); + pin(0).set_name(perm_string::literal("Result")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("DataA"), 0); + pin(1).set_name(perm_string::literal("DataA")); pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("DataB"), 0); + pin(2).set_name(perm_string::literal("DataB")); } NetPow::~NetPow() @@ -1719,13 +1719,13 @@ NetMux::NetMux(NetScope*s, perm_string n, width_(wi), size_(si), swidth_(sw) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Q"), 0); + pin(0).set_name(perm_string::literal("Q")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("Sel"), 0); + pin(1).set_name(perm_string::literal("Sel")); for (unsigned idx = 0 ; idx < size_ ; idx += 1) { pin_Data(idx).set_dir(Link::INPUT); - pin_Data(idx).set_name(perm_string::literal("D"), idx); + pin_Data(idx).set_name(perm_string::literal("D")); } } @@ -1785,8 +1785,8 @@ NetSignExtend::NetSignExtend(NetScope*s, perm_string n, unsigned w) { pin(0).set_dir(Link::OUTPUT); pin(1).set_dir(Link::INPUT); - pin(0).set_name(perm_string::literal("O"), 0); - pin(1).set_name(perm_string::literal("I"), 0); + pin(0).set_name(perm_string::literal("O")); + pin(1).set_name(perm_string::literal("I")); } NetSignExtend::~NetSignExtend() @@ -1803,8 +1803,8 @@ NetBUFZ::NetBUFZ(NetScope*s, perm_string n, unsigned w) { pin(0).set_dir(Link::OUTPUT); pin(1).set_dir(Link::INPUT); - pin(0).set_name(perm_string::literal("O"), 0); - pin(1).set_name(perm_string::literal("I"), 0); + pin(0).set_name(perm_string::literal("O")); + pin(1).set_name(perm_string::literal("I")); } NetBUFZ::~NetBUFZ() @@ -1819,9 +1819,9 @@ unsigned NetBUFZ::width() const NetCaseCmp::NetCaseCmp(NetScope*s, perm_string n, unsigned wid, bool eeq) : NetNode(s, n, 3), width_(wid), eeq_(eeq) { - pin(0).set_dir(Link::OUTPUT); pin(0).set_name(perm_string::literal("O"),0); - pin(1).set_dir(Link::INPUT); pin(1).set_name(perm_string::literal("I"),0); - pin(2).set_dir(Link::INPUT); pin(2).set_name(perm_string::literal("I"),1); + pin(0).set_dir(Link::OUTPUT); pin(0).set_name(perm_string::literal("O")); + pin(1).set_dir(Link::INPUT); pin(1).set_name(perm_string::literal("I0")); + pin(2).set_dir(Link::INPUT); pin(2).set_name(perm_string::literal("I1")); } NetCaseCmp::~NetCaseCmp() @@ -1880,7 +1880,7 @@ NetConst::NetConst(NetScope*s, perm_string n, verinum::V v) : NetNode(s, n, 1), width_(1) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O"), 0); + pin(0).set_name(perm_string::literal("O")); value_ = new verinum::V[1]; value_[0] = v; } @@ -1889,7 +1889,7 @@ NetConst::NetConst(NetScope*s, perm_string n, const verinum&val) : NetNode(s, n, 1), width_(val.len()) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O"), 0); + pin(0).set_name(perm_string::literal("O")); value_ = new verinum::V[width_]; for (unsigned idx = 0 ; idx < width_ ; idx += 1) { value_[idx] = val.get(idx); @@ -2418,10 +2418,10 @@ NetLogic::NetLogic(NetScope*s, perm_string n, unsigned pins, : NetNode(s, n, pins), type_(t), width_(wid) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O"), 0); + pin(0).set_name(perm_string::literal("O")); for (unsigned idx = 1 ; idx < pins ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).set_name(perm_string::literal("I"), idx-1); + pin(idx).set_name(perm_string::literal("I")); } } diff --git a/netlist.h b/netlist.h index b693db836..e79fe2141 100644 --- a/netlist.h +++ b/netlist.h @@ -259,9 +259,8 @@ class Link { // A link of an object (sometimes called a "pin") has a // name. It is convenient for the name to have a string and an // integer part. - void set_name(perm_string, unsigned inst =0); + void set_name(perm_string); perm_string get_name() const; - unsigned get_inst() const; private: // The NetNode manages these. They point back to the @@ -277,7 +276,6 @@ class Link { // has width, then the inst_ member is the index of the // pin. perm_string name_; - unsigned inst_; private: Link *next_; From 3abf51dcadffa3287c4d891ec27fdc62f7c050f6 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 10 Sep 2008 19:34:28 -0700 Subject: [PATCH 37/93] Get rid of names attached to Links. This is simply no need for the names on links, other then for debug messages, and there are better ways to handle that. --- design_dump.cc | 2 +- net_event.cc | 1 - net_func.cc | 6 +- net_link.cc | 17 +----- net_modulo.cc | 9 +-- net_tran.cc | 11 ++-- net_udp.cc | 2 - netlist.cc | 152 +++++++++++-------------------------------------- netlist.h | 11 ---- 9 files changed, 45 insertions(+), 166 deletions(-) diff --git a/design_dump.cc b/design_dump.cc index ad1c89af8..87deca3dd 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -244,7 +244,7 @@ void NetNode::dump_node(ostream&o, unsigned ind) const void NetPins::dump_node_pins(ostream&o, unsigned ind) const { for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { - o << setw(ind) << "" << idx << " " << pin(idx).get_name(); + o << setw(ind) << "" << idx << " pin" << idx; switch (pin(idx).get_dir()) { case Link::PASSIVE: diff --git a/net_event.cc b/net_event.cc index 529eaf45a..3804ff8fb 100644 --- a/net_event.cc +++ b/net_event.cc @@ -251,7 +251,6 @@ NetEvProbe::NetEvProbe(NetScope*s, perm_string n, NetEvent*tgt, { for (unsigned idx = 0 ; idx < p ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).set_name(perm_string::literal("P")); } enext_ = event_->probes_; diff --git a/net_func.cc b/net_func.cc index f3037aa0a..8e4f05d7f 100644 --- a/net_func.cc +++ b/net_func.cc @@ -34,12 +34,10 @@ NetUserFunc::NetUserFunc(NetScope*s, perm_string n, NetScope*d) def_(d) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(def_->basename()); for (unsigned idx = 1 ; idx < pin_count() ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).set_name(perm_string::literal("D")); pin(idx).drive0(Link::HIGHZ); pin(idx).drive1(Link::HIGHZ); } @@ -135,13 +133,11 @@ NetSysFunc::NetSysFunc(NetScope*s, perm_string n, { def_ = def; - pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Q")); + pin(0).set_dir(Link::OUTPUT); // Q for (unsigned idx = 1 ; idx < pin_count() ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).set_name(perm_string::literal("D")); pin(idx).drive0(Link::HIGHZ); pin(idx).drive1(Link::HIGHZ); } diff --git a/net_link.cc b/net_link.cc index f3e1709ea..e36675905 100644 --- a/net_link.cc +++ b/net_link.cc @@ -206,16 +206,6 @@ unsigned Link::get_pin() const return pin_; } -void Link::set_name(perm_string n) -{ - name_ = n; -} - -perm_string Link::get_name() const -{ - return name_; -} - Nexus::Nexus() { name_ = 0; @@ -447,10 +437,9 @@ const char* Nexus::name() const const Link*lnk = first_nlink(); const NetObj*obj = dynamic_cast(lnk->get_obj()); pin = lnk->get_pin(); - cerr << "internal error: No signal for nexus of " << - obj->name() << " pin " << pin << "(" << - lnk->get_name() << ")" - " type=" << typeid(*obj).name() << "?" << endl; + cerr << "internal error: No signal for nexus of " + << obj->name() << " pin " << pin + << " type=" << typeid(*obj).name() << "?" << endl; } assert(sig); diff --git a/net_modulo.cc b/net_modulo.cc index d36571b12..de99a4dba 100644 --- a/net_modulo.cc +++ b/net_modulo.cc @@ -40,12 +40,9 @@ NetModulo::NetModulo(NetScope*s, perm_string n, unsigned wr, : NetNode(s, n, 3), width_r_(wr), width_a_(wa), width_b_(wb) { - pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result")); - pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("DataA")); - pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("DataB")); + pin(0).set_dir(Link::OUTPUT); // Result + pin(1).set_dir(Link::INPUT); // DataA + pin(2).set_dir(Link::INPUT); // DataB } NetModulo::~NetModulo() diff --git a/net_tran.cc b/net_tran.cc index e07c8a1da..baa37b410 100644 --- a/net_tran.cc +++ b/net_tran.cc @@ -45,19 +45,18 @@ static bool has_enable(ivl_switch_type_t tt) NetTran::NetTran(NetScope*scope, perm_string n, ivl_switch_type_t tt) : NetNode(scope, n, has_enable(tt)? 3 : 2), type_(tt) { - pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A")); - pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B")); + pin(0).set_dir(Link::PASSIVE); + pin(1).set_dir(Link::PASSIVE); if (pin_count() == 3) { - pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("E")); + pin(2).set_dir(Link::INPUT); // Enable } } NetTran::NetTran(NetScope*scope, perm_string n, unsigned wid, unsigned part, unsigned off) : NetNode(scope, n, 2), type_(IVL_SW_TRAN_VP), wid_(wid), part_(part), off_(off) { - pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A")); - pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B")); + pin(0).set_dir(Link::PASSIVE); + pin(1).set_dir(Link::PASSIVE); } NetTran::~NetTran() diff --git a/net_udp.cc b/net_udp.cc index b371d4195..8924027f5 100644 --- a/net_udp.cc +++ b/net_udp.cc @@ -30,10 +30,8 @@ NetUDP::NetUDP(NetScope*s, perm_string n, unsigned pins, PUdp *u) : NetNode(s, n, pins), udp(u) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O")); for (unsigned idx = 1 ; idx < pins ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).set_name(perm_string::literal("I")); } } diff --git a/netlist.cc b/netlist.cc index a1f22daa0..112e097ed 100644 --- a/netlist.cc +++ b/netlist.cc @@ -238,9 +238,7 @@ NetNode::~NetNode() NetBranch::NetBranch(discipline_t*dis) : NetPins(2), discipline_(dis) { - pin(0).set_name(perm_string::literal("A")); pin(0).set_dir(Link::PASSIVE); - pin(1).set_name(perm_string::literal("B")); pin(1).set_dir(Link::PASSIVE); } @@ -266,13 +264,11 @@ NetDelaySrc::NetDelaySrc(NetScope*s, perm_string n, unsigned npins, posedge_ = false; negedge_ = false; for (unsigned idx = 0 ; idx < npins ; idx += 1) { - pin(idx).set_name(perm_string::literal("I")); pin(idx).set_dir(Link::INPUT); } if (condit_src) { condit_flag_ = true; - pin(npins).set_name(perm_string::literal("COND")); pin(npins).set_dir(Link::INPUT); } } @@ -455,7 +451,6 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins) break; } - pin(0).set_name(perm_string::literal("P")); pin(0).set_dir(dir); pin(0).set_init(init_value); @@ -494,7 +489,6 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, } for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { - pin(idx).set_name(perm_string::literal("P")); pin(idx).set_dir(dir); pin(idx).set_init(init_value); } @@ -542,7 +536,6 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, } for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { - pin(idx).set_name(perm_string::literal("P")); pin(idx).set_dir(dir); pin(idx).set_init(init_value); } @@ -799,8 +792,6 @@ NetPartSelect::NetPartSelect(NetNet*sig, unsigned off, unsigned wid, pin(1).set_dir(Link::OUTPUT); break; } - pin(0).set_name(perm_string::literal("Part")); - pin(1).set_name(perm_string::literal("Vect")); } NetPartSelect::NetPartSelect(NetNet*sig, NetNet*sel, @@ -822,10 +813,6 @@ NetPartSelect::NetPartSelect(NetNet*sig, NetNet*sel, break; } pin(2).set_dir(Link::INPUT); - - pin(0).set_name(perm_string::literal("Part")); - pin(1).set_name(perm_string::literal("Vect")); - pin(2).set_name(perm_string::literal("Select")); } NetPartSelect::~NetPartSelect() @@ -890,28 +877,22 @@ NetCastInt::NetCastInt(NetScope*scope, perm_string n, unsigned width) : NetNode(scope, n, 2), width_(width) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("I")); } NetCastReal::NetCastReal(NetScope*scope, perm_string n, bool signed_flag) : NetNode(scope, n, 2), signed_flag_(signed_flag) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("I")); } NetConcat::NetConcat(NetScope*scope, perm_string n, unsigned wid, unsigned cnt) : NetNode(scope, n, cnt+1), width_(wid) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O")); for (unsigned idx = 1 ; idx < cnt+1 ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).set_name(perm_string::literal("I")); } } @@ -929,9 +910,7 @@ NetReplicate::NetReplicate(NetScope*scope, perm_string n, : NetNode(scope, n, 2), width_(wid), repeat_(rpt) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("I")); } NetReplicate::~NetReplicate() @@ -966,21 +945,13 @@ NetFF::NetFF(NetScope*s, perm_string n, unsigned width) : NetNode(s, n, 8), width_(width) { pin_Clock().set_dir(Link::INPUT); - pin_Clock().set_name(perm_string::literal("Clock")); pin_Enable().set_dir(Link::INPUT); - pin_Enable().set_name(perm_string::literal("Enable")); pin_Aset().set_dir(Link::INPUT); - pin_Aset().set_name(perm_string::literal("Aset")); pin_Aclr().set_dir(Link::INPUT); - pin_Aclr().set_name(perm_string::literal("Aclr")); pin_Sset().set_dir(Link::INPUT); - pin_Sset().set_name(perm_string::literal("Sset")); pin_Sclr().set_dir(Link::INPUT); - pin_Sclr().set_name(perm_string::literal("Sclr")); pin_Data().set_dir(Link::INPUT); - pin_Data().set_name(perm_string::literal("Data")); pin_Q().set_dir(Link::OUTPUT); - pin_Q().set_name(perm_string::literal("Q")); } NetFF::~NetFF() @@ -1097,9 +1068,7 @@ NetAbs::NetAbs(NetScope*s, perm_string n, unsigned w) : NetNode(s, n, 2), width_(w) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("DataA")); } NetAbs::~NetAbs() @@ -1128,23 +1097,14 @@ NetAddSub::NetAddSub(NetScope*s, perm_string n, unsigned w) : NetNode(s, n, 9), width_(w) { pin(0).set_dir(Link::INPUT); - pin(0).set_name(perm_string::literal("Add_Sub")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("Aclr")); pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("Clock")); pin(3).set_dir(Link::INPUT); - pin(3).set_name(perm_string::literal("Cin")); pin(4).set_dir(Link::OUTPUT); - pin(4).set_name(perm_string::literal("Cout")); pin(5).set_dir(Link::OUTPUT); - pin(5).set_name(perm_string::literal("Overflow")); pin(6).set_dir(Link::INPUT); - pin(6).set_name(perm_string::literal("DataA")); pin(7).set_dir(Link::INPUT); - pin(7).set_name(perm_string::literal("DataB")); pin(8).set_dir(Link::OUTPUT); - pin(8).set_name(perm_string::literal("Result")); } NetAddSub::~NetAddSub() @@ -1200,10 +1160,8 @@ NetArrayDq::NetArrayDq(NetScope*s, perm_string n, NetNet*mem, unsigned awid) : NetNode(s, n, 2), mem_(mem), awidth_(awid) { - pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result")); - pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("Address")); + pin(0).set_dir(Link::OUTPUT); // Result + pin(1).set_dir(Link::INPUT); // Address // Increment the expression reference count for the target // memory so that it is not deleted underneath me. mem->incr_eref(); @@ -1261,12 +1219,9 @@ NetCLShift::NetCLShift(NetScope*s, perm_string n, width_(width), width_dist_(width_dist), right_flag_(right_flag), signed_flag_(signed_flag) { - pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result")); - pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("Data")); - pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("Distance")); + pin(0).set_dir(Link::OUTPUT); // Result + pin(1).set_dir(Link::INPUT); // Data + pin(2).set_dir(Link::INPUT); // Distance } NetCLShift::~NetCLShift() @@ -1327,26 +1282,16 @@ NetCompare::NetCompare(NetScope*s, perm_string n, unsigned wi) : NetNode(s, n, 10), width_(wi) { signed_flag_ = false; - pin(0).set_dir(Link::INPUT); pin(0).set_name( - perm_string::literal("Aclr")); - pin(1).set_dir(Link::INPUT); pin(1).set_name( - perm_string::literal("Clock")); - pin(2).set_dir(Link::OUTPUT); pin(2).set_name( - perm_string::literal("AGB")); - pin(3).set_dir(Link::OUTPUT); pin(3).set_name( - perm_string::literal("AGEB")); - pin(4).set_dir(Link::OUTPUT); pin(4).set_name( - perm_string::literal("AEB")); - pin(5).set_dir(Link::OUTPUT); pin(5).set_name( - perm_string::literal("ANEB")); - pin(6).set_dir(Link::OUTPUT); pin(6).set_name( - perm_string::literal("ALB")); - pin(7).set_dir(Link::OUTPUT); pin(7).set_name( - perm_string::literal("ALEB")); - pin(8).set_dir(Link::INPUT); - pin(8).set_name(perm_string::literal("DataA")); - pin(9).set_dir(Link::INPUT); - pin(9).set_name(perm_string::literal("DataB")); + pin(0).set_dir(Link::INPUT); // Aclr + pin(1).set_dir(Link::INPUT); // Clock + pin(2).set_dir(Link::OUTPUT); // AGB + pin(3).set_dir(Link::OUTPUT); // AGEB + pin(4).set_dir(Link::OUTPUT); // AEB + pin(5).set_dir(Link::OUTPUT); // ANEB + pin(6).set_dir(Link::OUTPUT); // ALB + pin(7).set_dir(Link::OUTPUT); // ALEB + pin(8).set_dir(Link::INPUT); // DataA + pin(9).set_dir(Link::INPUT); // DataB } NetCompare::~NetCompare() @@ -1473,12 +1418,9 @@ NetDivide::NetDivide(NetScope*sc, perm_string n, unsigned wr, : NetNode(sc, n, 3), width_r_(wr), width_a_(wa), width_b_(wb), signed_flag_(false) { - pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result")); - pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("DataA")); - pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("DataB")); + pin(0).set_dir(Link::OUTPUT); // Result + pin(1).set_dir(Link::INPUT); // DataA + pin(2).set_dir(Link::INPUT); // DataB } NetDivide::~NetDivide() @@ -1544,7 +1486,6 @@ NetLiteral::NetLiteral(NetScope*sc, perm_string n, const verireal&val) : NetNode(sc, n, 1), real_(val) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O")); } NetLiteral::~NetLiteral() @@ -1566,12 +1507,9 @@ NetMult::NetMult(NetScope*sc, perm_string n, unsigned wr, : NetNode(sc, n, 3), signed_(false), width_r_(wr), width_a_(wa), width_b_(wb) { - pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result")); - pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("DataA")); - pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("DataB")); + pin(0).set_dir(Link::OUTPUT); // Result + pin(1).set_dir(Link::INPUT); // DataA + pin(2).set_dir(Link::INPUT); // DataB } NetMult::~NetMult() @@ -1638,12 +1576,9 @@ NetPow::NetPow(NetScope*sc, perm_string n, unsigned wr, : NetNode(sc, n, 3), signed_(false), width_r_(wr), width_a_(wa), width_b_(wb) { - pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Result")); - pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("DataA")); - pin(2).set_dir(Link::INPUT); - pin(2).set_name(perm_string::literal("DataB")); + pin(0).set_dir(Link::OUTPUT); // Result + pin(1).set_dir(Link::INPUT); // DataA + pin(2).set_dir(Link::INPUT); // DataB } NetPow::~NetPow() @@ -1718,14 +1653,11 @@ NetMux::NetMux(NetScope*s, perm_string n, : NetNode(s, n, 2+si), width_(wi), size_(si), swidth_(sw) { - pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("Q")); - pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("Sel")); + pin(0).set_dir(Link::OUTPUT); // Q + pin(1).set_dir(Link::INPUT); // Sel for (unsigned idx = 0 ; idx < size_ ; idx += 1) { - pin_Data(idx).set_dir(Link::INPUT); - pin_Data(idx).set_name(perm_string::literal("D")); + pin_Data(idx).set_dir(Link::INPUT); // Data[idx] } } @@ -1785,8 +1717,6 @@ NetSignExtend::NetSignExtend(NetScope*s, perm_string n, unsigned w) { pin(0).set_dir(Link::OUTPUT); pin(1).set_dir(Link::INPUT); - pin(0).set_name(perm_string::literal("O")); - pin(1).set_name(perm_string::literal("I")); } NetSignExtend::~NetSignExtend() @@ -1803,8 +1733,6 @@ NetBUFZ::NetBUFZ(NetScope*s, perm_string n, unsigned w) { pin(0).set_dir(Link::OUTPUT); pin(1).set_dir(Link::INPUT); - pin(0).set_name(perm_string::literal("O")); - pin(1).set_name(perm_string::literal("I")); } NetBUFZ::~NetBUFZ() @@ -1819,9 +1747,9 @@ unsigned NetBUFZ::width() const NetCaseCmp::NetCaseCmp(NetScope*s, perm_string n, unsigned wid, bool eeq) : NetNode(s, n, 3), width_(wid), eeq_(eeq) { - pin(0).set_dir(Link::OUTPUT); pin(0).set_name(perm_string::literal("O")); - pin(1).set_dir(Link::INPUT); pin(1).set_name(perm_string::literal("I0")); - pin(2).set_dir(Link::INPUT); pin(2).set_name(perm_string::literal("I1")); + pin(0).set_dir(Link::OUTPUT); + pin(1).set_dir(Link::INPUT); + pin(2).set_dir(Link::INPUT); } NetCaseCmp::~NetCaseCmp() @@ -1880,7 +1808,6 @@ NetConst::NetConst(NetScope*s, perm_string n, verinum::V v) : NetNode(s, n, 1), width_(1) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O")); value_ = new verinum::V[1]; value_[0] = v; } @@ -1889,7 +1816,6 @@ NetConst::NetConst(NetScope*s, perm_string n, const verinum&val) : NetNode(s, n, 1), width_(val.len()) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O")); value_ = new verinum::V[width_]; for (unsigned idx = 0 ; idx < width_ ; idx += 1) { value_[idx] = val.get(idx); @@ -1920,12 +1846,7 @@ NetFuncDef::NetFuncDef(NetScope*s, NetNet*result, const svector&po) NetFuncDef::~NetFuncDef() { } -#if 0 -const string NetFuncDef::name() const -{ - return scope_->name(); -} -#endif + const NetScope* NetFuncDef::scope() const { return scope_; @@ -2049,12 +1970,7 @@ NetUTask::NetUTask(NetScope*def) NetUTask::~NetUTask() { } -#if 0 -const string NetUTask::name() const -{ - return task_->name(); -} -#endif + const NetScope* NetUTask::task() const { return task_; @@ -2418,10 +2334,8 @@ NetLogic::NetLogic(NetScope*s, perm_string n, unsigned pins, : NetNode(s, n, pins), type_(t), width_(wid) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O")); for (unsigned idx = 1 ; idx < pins ; idx += 1) { pin(idx).set_dir(Link::INPUT); - pin(idx).set_name(perm_string::literal("I")); } } @@ -2440,9 +2354,7 @@ NetUReduce::NetUReduce(NetScope*scope, perm_string n, : NetNode(scope, n, 2), type_(t), width_(wid) { pin(0).set_dir(Link::OUTPUT); - pin(0).set_name(perm_string::literal("O")); pin(1).set_dir(Link::INPUT); - pin(1).set_name(perm_string::literal("I")); } NetUReduce::TYPE NetUReduce::type() const diff --git a/netlist.h b/netlist.h index e79fe2141..1cb4ea890 100644 --- a/netlist.h +++ b/netlist.h @@ -256,12 +256,6 @@ class Link { NetPins*get_obj(); unsigned get_pin() const; - // A link of an object (sometimes called a "pin") has a - // name. It is convenient for the name to have a string and an - // integer part. - void set_name(perm_string); - perm_string get_name() const; - private: // The NetNode manages these. They point back to the // NetNode so that following the links can get me here. @@ -272,11 +266,6 @@ class Link { strength_t drive0_, drive1_; verinum::V init_; - // These members name the pin of the link. If the name - // has width, then the inst_ member is the index of the - // pin. - perm_string name_; - private: Link *next_; Nexus*nexus_; From cdfb2315cf7323ed813b47801de161cc8301a3cb Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Wed, 10 Sep 2008 11:07:58 -0700 Subject: [PATCH 38/93] One more signed vs unsigned comparison fix Introduced in a8ad505af78289a44350a0dbfa1441c1ecf5e92e Various improgements to expression ::synthesize methods --- expr_synth.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/expr_synth.cc b/expr_synth.cc index d323b7dd3..28f6d449f 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -952,9 +952,9 @@ NetNet* NetESelect::synthesize(Design *des, NetScope*scope) below->set_line(*this); } - // Any above bits?. + // Any above bits? NetNet*above = 0; - if (base_val+select_width > sub->vector_width()) { + if ((unsigned)base_val+select_width > sub->vector_width()) { select_width = sub->vector_width() - base_val; unsigned above_width = expr_width() - select_width; From 1e60754ff03f9012edd913040350755ffef5ba19 Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 10 Sep 2008 19:37:11 -0700 Subject: [PATCH 39/93] Partial non-blocking event control implementation This patch pushes the non-blocking event control information to the code generator. It adds the %evctl statements that are used to put the event control information into the special thread event control registers. The signed version (%evctl/s) required the implementation of %ix/getv/s to load a signed value into an index register. It then adds %assign/wr/e event control based non-blocking assignment for real values. It also fixes the other non-blocking real assignments to use Transport instead of inertial delays. --- design_dump.cc | 24 ++++++++++ elaborate.cc | 39 +++++++++++----- net_assign.cc | 57 +++++++++--------------- netlist.h | 13 +++++- t-dll-api.cc | 14 ++++++ t-dll-proc.cc | 97 +++++++++++++++++++++++++++++++++++++++- t-dll.h | 7 +++ tgt-vvp/eval_expr.c | 4 +- tgt-vvp/vvp_process.c | 62 +++++++++++++++++++++++++- vvp/codes.h | 5 +++ vvp/compile.cc | 9 +++- vvp/event.cc | 101 ++++++++++++++++++++++++------------------ vvp/event.h | 73 +++++++++++++----------------- vvp/opcodes.txt | 24 ++++++++-- vvp/vthread.cc | 87 +++++++++++++++++++++++++++++++++++- 15 files changed, 471 insertions(+), 145 deletions(-) diff --git a/design_dump.cc b/design_dump.cc index 87deca3dd..c90e7262c 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -758,6 +758,11 @@ void NetAssignNB::dump(ostream&o, unsigned ind) const if (const NetExpr*de = get_delay()) o << "#(" << *de << ") "; + if (count_) + o << "repeat(" << *count_ << ") "; + if (event_) { + o << *event_; + } o << *rval() << ";" << endl; @@ -902,6 +907,25 @@ void NetEvWait::dump(ostream&o, unsigned ind) const o << setw(ind+2) << "" << "/* noop */ ;" << endl; } +ostream& operator << (ostream&out, const NetEvWait&obj) +{ + obj.dump_inline(out); + return out; +} + +void NetEvWait::dump_inline(ostream&o) const +{ + o << "@("; + + if (nevents() > 0) + o << event(0)->name(); + + for (unsigned idx = 1 ; idx < nevents() ; idx += 1) + o << " or " << event(idx)->name(); + + o << ") "; +} + void NetForce::dump(ostream&o, unsigned ind) const { o << setw(ind) << "" << "force "; diff --git a/elaborate.cc b/elaborate.cc index 63240538d..a2cb6e6c0 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1906,11 +1906,14 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const } NetExpr*delay = 0; - if (delay_ != 0) + if (delay_ != 0) { + assert(count_ == 0 && event_ == 0); delay = elaborate_delay_expr(delay_, des, scope); + } + NetExpr*count = 0; + NetEvWait*event = 0; if (count_ != 0 || event_ != 0) { - NetExpr*count = 0; if (count_ != 0) { assert(event_ != 0); count = elab_and_eval(des, scope, count_, -1); @@ -1918,27 +1921,39 @@ NetProc* PAssignNB::elaborate(Design*des, NetScope*scope) const cerr << get_fileline() << ": Unable to elaborate " "repeat expression." << endl; des->errors += 1; -// return 0; + return 0; } } - NetProc* event = event_->elaborate(des, scope); - if (event == 0) { + NetProc*st = event_->elaborate(des, scope); + if (st == 0) { cerr << get_fileline() << ": unable to elaborate " "event expression." << endl; des->errors += 1; -// return 0; + return 0; } + event = dynamic_cast(st) ; + assert(event); - cerr << get_fileline() << ": sorry: non blocking "; - if (count_) cerr << "repeat "; - cerr << "event controls are not supported." << endl; - des->errors += 1; - return 0; + // Some constant values are special. + if (NetEConst*ce = dynamic_cast(count)) { + long val = ce->value().as_long(); + // We only need the assignment statement. + if (val <= 0) { + delete count; + delete event; + count = 0; + event = 0; + // We only need the event. + } else if (val == 1) { + delete count; + count = 0; + } + } } /* All done with this node. Mark its line number and check it in. */ - NetAssignNB*cur = new NetAssignNB(lv, rv); + NetAssignNB*cur = new NetAssignNB(lv, rv, event, count); cur->set_delay(delay); cur->set_line(*this); return cur; diff --git a/net_assign.cc b/net_assign.cc index 485b2cc45..4b84e6324 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 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 @@ -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: net_assign.cc,v 1.22 2007/01/16 05:44:15 steve Exp $" -#endif # include "config.h" @@ -212,15 +209,34 @@ NetAssign::~NetAssign() { } -NetAssignNB::NetAssignNB(NetAssign_*lv, NetExpr*rv) +NetAssignNB::NetAssignNB(NetAssign_*lv, NetExpr*rv, NetEvWait*ev, NetExpr*cnt) : NetAssignBase(lv, rv) { + event_ = ev; + count_ = cnt; } NetAssignNB::~NetAssignNB() { } +unsigned NetAssignNB::nevents() const +{ + if (event_) return event_->nevents(); + return 0; +} + +const NetEvent*NetAssignNB::event(unsigned idx) const +{ + if (event_) return event_->event(idx); + return 0; +} + +const NetExpr*NetAssignNB::get_count() const +{ + return count_; +} + NetCAssign::NetCAssign(NetAssign_*lv, NetExpr*rv) : NetAssignBase(lv, rv) { @@ -256,34 +272,3 @@ NetRelease::NetRelease(NetAssign_*l) NetRelease::~NetRelease() { } - -/* - * $Log: net_assign.cc,v $ - * Revision 1.22 2007/01/16 05:44:15 steve - * Major rework of array handling. Memories are replaced with the - * more general concept of arrays. The NetMemory and NetEMemory - * classes are removed from the ivl core program, and the IVL_LPM_RAM - * lpm type is removed from the ivl_target API. - * - * Revision 1.21 2006/02/02 02:43:58 steve - * Allow part selects of memory words in l-values. - * - * Revision 1.20 2005/07/11 16:56:50 steve - * Remove NetVariable and ivl_variable_t structures. - * - * Revision 1.19 2004/12/11 02:31:26 steve - * Rework of internals to carry vectors through nexus instead - * of single bits. Make the ivl, tgt-vvp and vvp initial changes - * down this path. - * - * Revision 1.18 2004/08/28 15:08:31 steve - * Do not change reg to wire in NetAssign_ unless synthesizing. - * - * Revision 1.17 2004/02/18 17:11:56 steve - * Use perm_strings for named langiage items. - * - * Revision 1.16 2003/01/26 21:15:58 steve - * Rework expression parsing and elaboration to - * accommodate real/realtime values and expressions. - */ - diff --git a/netlist.h b/netlist.h index 1cb4ea890..4777cf700 100644 --- a/netlist.h +++ b/netlist.h @@ -2230,7 +2230,8 @@ class NetAssign : public NetAssignBase { class NetAssignNB : public NetAssignBase { public: - explicit NetAssignNB(NetAssign_*lv, NetExpr*rv); + explicit NetAssignNB(NetAssign_*lv, NetExpr*rv, NetEvWait*ev, + NetExpr*cnt); ~NetAssignNB(); @@ -2238,7 +2239,13 @@ class NetAssignNB : public NetAssignBase { virtual int match_proc(struct proc_match_t*); virtual void dump(ostream&, unsigned ind) const; + unsigned nevents() const; + const NetEvent*event(unsigned) const; + const NetExpr* get_count() const; + private: + NetEvWait*event_; + NetExpr*count_; }; /* @@ -2620,6 +2627,8 @@ class NetEvWait : public NetProc { const svector&events); virtual void dump(ostream&, unsigned ind) const; + // This will ignore any statement. + virtual void dump_inline(ostream&) const; virtual DelayType delay_type() const; private: @@ -2629,6 +2638,8 @@ class NetEvWait : public NetProc { NetEvent**events_; }; +ostream& operator << (ostream&out, const NetEvWait&obj); + class NetEvProbe : public NetNode { friend class NetEvent; diff --git a/t-dll-api.cc b/t-dll-api.cc index 5d9c49c41..d5ab959ea 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -1972,6 +1972,9 @@ extern "C" ivl_statement_t ivl_stmt_case_stmt(ivl_statement_t net, unsigned idx) extern "C" ivl_expr_t ivl_stmt_cond_expr(ivl_statement_t net) { switch (net->type_) { + case IVL_ST_ASSIGN_NB: + return net->u_.assign_.count; + case IVL_ST_CONDIT: return net->u_.condit_.cond_; @@ -2034,6 +2037,9 @@ extern "C" uint64_t ivl_stmt_delay_val(ivl_statement_t net) extern "C" unsigned ivl_stmt_nevent(ivl_statement_t net) { switch (net->type_) { + case IVL_ST_ASSIGN_NB: + return net->u_.assign_.nevent; + case IVL_ST_WAIT: return net->u_.wait_.nevent; @@ -2049,6 +2055,13 @@ extern "C" unsigned ivl_stmt_nevent(ivl_statement_t net) extern "C" ivl_event_t ivl_stmt_events(ivl_statement_t net, unsigned idx) { switch (net->type_) { + case IVL_ST_ASSIGN_NB: + assert(idx < net->u_.assign_.nevent); + if (net->u_.assign_.nevent == 1) + return net->u_.assign_.event; + else + return net->u_.assign_.events[idx]; + case IVL_ST_WAIT: assert(idx < net->u_.wait_.nevent); if (net->u_.wait_.nevent == 1) @@ -2059,6 +2072,7 @@ extern "C" ivl_event_t ivl_stmt_events(ivl_statement_t net, unsigned idx) case IVL_ST_TRIGGER: assert(idx == 0); return net->u_.wait_.event; + default: assert(0); } diff --git a/t-dll-proc.cc b/t-dll-proc.cc index 8e26f6d3d..badf7cd78 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -59,7 +59,7 @@ bool dll_target::process(const NetProcTop*net) /* This little bit causes the process to be completely generated so that it can be passed to the DLL. The - stmt_cur_ member us used to hold a pointer to the current + stmt_cur_ member is used to hold a pointer to the current statement in progress, and the emit_proc() method fills in that object. @@ -222,6 +222,7 @@ bool dll_target::proc_assign(const NetAssign*net) void dll_target::proc_assign_nb(const NetAssignNB*net) { const NetExpr* delay_exp = net->get_delay(); + const NetExpr* cnt_exp = net->get_count(); assert(stmt_cur_); assert(stmt_cur_->type_ == IVL_ST_NONE); @@ -229,6 +230,8 @@ void dll_target::proc_assign_nb(const NetAssignNB*net) FILE_NAME(stmt_cur_, net); stmt_cur_->u_.assign_.delay = 0; + stmt_cur_->u_.assign_.count = 0; + stmt_cur_->u_.assign_.nevent = 0; /* Make the lval fields. */ make_assign_lvals_(net); @@ -239,6 +242,7 @@ void dll_target::proc_assign_nb(const NetAssignNB*net) stmt_cur_->u_.assign_.rval_ = expr_; expr_ = 0; + /* Process a delay if it exists. */ if (const NetEConst*delay_num = dynamic_cast(delay_exp)) { verinum val = delay_num->value(); ivl_expr_t de = new struct ivl_expr_s; @@ -253,6 +257,96 @@ void dll_target::proc_assign_nb(const NetAssignNB*net) stmt_cur_->u_.assign_.delay = expr_; expr_ = 0; } + + /* Process a count if it exists. */ + if (const NetEConst*cnt_num = dynamic_cast(cnt_exp)) { + verinum val = cnt_num->value(); + ivl_expr_t cnt = new struct ivl_expr_s; + cnt->type_ = IVL_EX_ULONG; + cnt->width_ = 8 * sizeof(unsigned long); + cnt->signed_ = 0; + cnt->u_.ulong_.value = val.as_ulong(); + stmt_cur_->u_.assign_.count = cnt; + + } else if (cnt_exp != 0) { + cnt_exp->expr_scan(this); + stmt_cur_->u_.assign_.count = expr_; + expr_ = 0; + } + + /* Process the events if they exist. This is a copy of code + * from NetEvWait below. */ + if (net->nevents() > 0) { + stmt_cur_->u_.assign_.nevent = net->nevents(); + if (net->nevents() > 1) { + stmt_cur_->u_.assign_.events = (ivl_event_t*) + calloc(net->nevents(), sizeof(ivl_event_t*)); + } + + for (unsigned edx = 0 ; edx < net->nevents() ; edx += 1) { + + /* Locate the event by name. Save the ivl_event_t in the + statement so that the generator can find it easily. */ + const NetEvent*ev = net->event(edx); + ivl_scope_t ev_scope = lookup_scope_(ev->scope()); + ivl_event_t ev_tmp=0; + + assert(ev_scope); + assert(ev_scope->nevent_ > 0); + for (unsigned idx = 0; idx < ev_scope->nevent_; idx += 1) { + const char*ename = + ivl_event_basename(ev_scope->event_[idx]); + if (strcmp(ev->name(), ename) == 0) { + ev_tmp = ev_scope->event_[idx]; + break; + } + } + // XXX should we assert(ev_tmp)? + + if (net->nevents() == 1) + stmt_cur_->u_.assign_.event = ev_tmp; + else + stmt_cur_->u_.assign_.events[edx] = ev_tmp; + + /* If this is an event with a probe, then connect up the + pins. This wasn't done during the ::event method because + the signals weren't scanned yet. */ + + if (ev->nprobe() >= 1) { + unsigned iany = 0; + unsigned ineg = ev_tmp->nany; + unsigned ipos = ineg + ev_tmp->nneg; + + for (unsigned idx = 0; idx < ev->nprobe(); idx += 1) { + const NetEvProbe*pr = ev->probe(idx); + unsigned base = 0; + + switch (pr->edge()) { + case NetEvProbe::ANYEDGE: + base = iany; + iany += pr->pin_count(); + break; + case NetEvProbe::NEGEDGE: + base = ineg; + ineg += pr->pin_count(); + break; + case NetEvProbe::POSEDGE: + base = ipos; + ipos += pr->pin_count(); + break; + } + + for (unsigned bit = 0; bit < pr->pin_count(); + bit += 1) { + ivl_nexus_t nex = (ivl_nexus_t) + pr->pin(bit).nexus()->t_cookie(); + assert(nex); + ev_tmp->pins[base+bit] = nex; + } + } + } + } + } } bool dll_target::proc_block(const NetBlock*net) @@ -643,6 +737,7 @@ bool dll_target::proc_wait(const NetEvWait*net) stmt_cur_->u_.wait_.stmt_ = (struct ivl_statement_s*) calloc(1, sizeof(struct ivl_statement_s)); + // This event processing code is also in the NB assign above. stmt_cur_->u_.wait_.nevent = net->nevents(); if (net->nevents() > 1) { stmt_cur_->u_.wait_.events = (ivl_event_t*) diff --git a/t-dll.h b/t-dll.h index 02a6418c8..87047b9d4 100644 --- a/t-dll.h +++ b/t-dll.h @@ -671,6 +671,13 @@ struct ivl_statement_s { struct ivl_lval_s*lval_; ivl_expr_t rval_; ivl_expr_t delay; + // The following are only for NB event control. + ivl_expr_t count; + unsigned nevent; + union { + ivl_event_t event; + ivl_event_t*events; + }; } assign_; struct { /* IVL_ST_BLOCK, IVL_ST_FORK */ diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 069ab9278..f9a2a89a7 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -162,7 +162,9 @@ static void eval_logic_into_integer(ivl_expr_t expr, unsigned ix) break; } } - fprintf(vvp_out, " %%ix/getv %u, v%p_%u;\n", ix, sig, word); + char*type = ivl_signal_signed(sig) ? "/s" : ""; + fprintf(vvp_out, " %%ix/getv%s %u, v%p_%u;\n", type, ix, + sig, word); break; } diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 861ce2232..14fba22e6 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -532,6 +532,7 @@ static int show_stmt_assign_nb_real(ivl_statement_t net) /* thread address for a word value. */ int word; unsigned long delay = 0; + unsigned nevents = ivl_stmt_nevent(net); /* Must be exactly 1 l-value. */ assert(ivl_stmt_lvals(net) == 1); @@ -557,13 +558,17 @@ static int show_stmt_assign_nb_real(ivl_statement_t net) /* We need to calculate the delay expression. */ if (del) { + assert(nevents == 0 && ivl_stmt_cond_expr(net) == 0); int delay_index = allocate_word(); draw_eval_expr_into_integer(del, delay_index); - fprintf(vvp_out, " %%assign/wr/d v%p_%lu, %d, %u;\n", + fprintf(vvp_out, " %%assign/wr/d v%p_%lu, %d, %u;\n", sig, use_word, delay_index, word); clr_word(delay_index); + } else if (nevents) { + fprintf(vvp_out, " %%assign/wr/e v%p_%lu, %u;\n", + sig, use_word, word); } else { - fprintf(vvp_out, " %%assign/wr v%p_%lu, %lu, %u;\n", + fprintf(vvp_out, " %%assign/wr v%p_%lu, %lu, %u;\n", sig, use_word, delay, word); } @@ -578,6 +583,49 @@ static int show_stmt_assign_nb(ivl_statement_t net) ivl_expr_t rval = ivl_stmt_rval(net); ivl_expr_t del = ivl_stmt_delay_expr(net); ivl_signal_t sig; + unsigned nevents = ivl_stmt_nevent(net); + + // If we have an event control build the control structure. + if (nevents) { + assert(del == 0); + + ivl_expr_t cnt = ivl_stmt_cond_expr(net); + unsigned long count = 1; + if (cnt && (ivl_expr_type(cnt) == IVL_EX_ULONG)) { + count = ivl_expr_uvalue(cnt); + cnt = 0; + } + + char name[256]; + if (nevents == 1) { + ivl_event_t ev = ivl_stmt_events(net, 0); + snprintf(name, sizeof(name), "E_%p", ev); + } else { + unsigned idx; + static unsigned int cascade_counter = 0; + ivl_event_t ev = ivl_stmt_events(net, 0); + fprintf(vvp_out, "Eassign_%u .event/or E_%p", + cascade_counter, ev); + + for (idx = 1; idx < nevents; idx += 1) { + ev = ivl_stmt_events(net, idx); + fprintf(vvp_out, ", E_%p", ev); + } + snprintf(name, sizeof(name), "Eassign_%u", cascade_counter); + cascade_counter += 1; + } + + if (cnt) { + int count_index = allocate_word(); + char*type = ivl_expr_signed(cnt) ? "/s" : ""; + draw_eval_expr_into_integer(cnt, count_index); + fprintf(vvp_out, " %%evctl%s %s, %d;\n", type, name, + count_index); + clr_word(count_index); + } else { + fprintf(vvp_out, " %%evctl/i %s, %lu;\n", name, count); + } + } unsigned long delay = 0; @@ -592,6 +640,16 @@ static int show_stmt_assign_nb(ivl_statement_t net) } } + if (nevents) { + fprintf(stderr, "%s:%u: vvp-tgt sorry: non-blocking ", + ivl_stmt_file(net), ivl_stmt_lineno(net)); + if (ivl_stmt_cond_expr(net)) { + fprintf(stderr, "repeat "); + } + fprintf(stderr, "event controls are not supported!\n"); + exit(1); + } + if (del && (ivl_expr_type(del) == IVL_EX_ULONG)) { delay = ivl_expr_uvalue(del); del = 0; diff --git a/vvp/codes.h b/vvp/codes.h index 3a803b5e6..1c5d87d4f 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -49,6 +49,7 @@ extern bool of_ASSIGN_V0X1(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_V0X1D(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_WR(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_WRD(vthread_t thr, vvp_code_t code); +extern bool of_ASSIGN_WRE(vthread_t thr, vvp_code_t code); extern bool of_ASSIGN_X0(vthread_t thr, vvp_code_t code); extern bool of_BLEND(vthread_t thr, vvp_code_t code); extern bool of_BLEND_WR(vthread_t thr, vvp_code_t code); @@ -78,6 +79,9 @@ extern bool of_DIV(vthread_t thr, vvp_code_t code); extern bool of_DIV_S(vthread_t thr, vvp_code_t code); extern bool of_DIV_WR(vthread_t thr, vvp_code_t code); extern bool of_END(vthread_t thr, vvp_code_t code); +extern bool of_EVCTL(vthread_t thr, vvp_code_t code); +extern bool of_EVCTLI(vthread_t thr, vvp_code_t code); +extern bool of_EVCTLS(vthread_t thr, vvp_code_t code); extern bool of_FORCE_LINK(vthread_t thr, vvp_code_t code); extern bool of_FORCE_V(vthread_t thr, vvp_code_t code); extern bool of_FORCE_WR(vthread_t thr, vvp_code_t code); @@ -87,6 +91,7 @@ extern bool of_INV(vthread_t thr, vvp_code_t code); extern bool of_IX_ADD(vthread_t thr, vvp_code_t code); extern bool of_IX_GET(vthread_t thr, vvp_code_t code); extern bool of_IX_GETV(vthread_t thr, vvp_code_t code); +extern bool of_IX_GETVS(vthread_t thr, vvp_code_t code); extern bool of_IX_GET_S(vthread_t thr, vvp_code_t code); extern bool of_IX_LOAD(vthread_t thr, vvp_code_t code); extern bool of_IX_MUL(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index bdf8d9262..821d7852f 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -92,8 +92,9 @@ const static struct opcode_table_s opcode_table[] = { { "%assign/v0/d",of_ASSIGN_V0D,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} }, { "%assign/v0/x1",of_ASSIGN_V0X1,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, { "%assign/v0/x1/d",of_ASSIGN_V0X1D,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, - { "%assign/wr",of_ASSIGN_WR,3,{OA_VPI_PTR,OA_BIT1, OA_BIT2} }, - { "%assign/wr/d",of_ASSIGN_WRD,3,{OA_VPI_PTR,OA_BIT1, OA_BIT2} }, + { "%assign/wr", of_ASSIGN_WR, 3,{OA_VPI_PTR, OA_BIT1, OA_BIT2} }, + { "%assign/wr/d",of_ASSIGN_WRD,3,{OA_VPI_PTR, OA_BIT1, OA_BIT2} }, + { "%assign/wr/e",of_ASSIGN_WRE,2,{OA_VPI_PTR, OA_BIT1, OA_NONE} }, { "%assign/x0",of_ASSIGN_X0,3,{OA_FUNC_PTR,OA_BIT1, OA_BIT2} }, { "%blend", of_BLEND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%blend/wr", of_BLEND_WR,2, {OA_BIT1, OA_BIT2, OA_NONE} }, @@ -122,6 +123,9 @@ const static struct opcode_table_s opcode_table[] = { { "%div/s", of_DIV_S, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%div/wr", of_DIV_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, { "%end", of_END, 0, {OA_NONE, OA_NONE, OA_NONE} }, + { "%evctl", of_EVCTL, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, + { "%evctl/i",of_EVCTLI, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, + { "%evctl/s",of_EVCTLS, 2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, { "%force/link",of_FORCE_LINK,2,{OA_FUNC_PTR,OA_FUNC_PTR2,OA_NONE} }, { "%force/v",of_FORCE_V,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} }, { "%force/wr",of_FORCE_WR,2, {OA_FUNC_PTR, OA_BIT1, OA_NONE} }, @@ -131,6 +135,7 @@ const static struct opcode_table_s opcode_table[] = { { "%ix/get", of_IX_GET, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%ix/get/s",of_IX_GET_S,3,{OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%ix/getv",of_IX_GETV,2, {OA_BIT1, OA_FUNC_PTR, OA_NONE} }, + { "%ix/getv/s",of_IX_GETVS,2, {OA_BIT1, OA_FUNC_PTR, OA_NONE} }, { "%ix/load",of_IX_LOAD,2, {OA_BIT1, OA_NUMBER, OA_NONE} }, { "%ix/mul", of_IX_MUL, 2, {OA_BIT1, OA_NUMBER, OA_NONE} }, { "%ix/sub", of_IX_SUB, 2, {OA_BIT1, OA_NUMBER, OA_NONE} }, diff --git a/vvp/event.cc b/vvp/event.cc index eeea27924..60f9dd620 100644 --- a/vvp/event.cc +++ b/vvp/event.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-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: event.cc,v 1.23 2006/12/09 19:06:53 steve Exp $" -#endif # include "event.h" # include "compile.h" @@ -37,6 +34,20 @@ void waitable_hooks_s::run_waiting_threads_() { + // Run the non-blocking event controls. + last = &event_ctls; + for (evctl*cur = event_ctls; cur != 0;) { + if (cur->dec_and_run()) { + evctl*nxt = cur->next; + delete cur; + cur = nxt; + *last = cur; + } else { + last = &(cur->next); + cur = cur->next; + } + } + if (threads == 0) return; @@ -45,6 +56,48 @@ void waitable_hooks_s::run_waiting_threads_() vthread_schedule_list(tmp); } +evctl::evctl(unsigned long ecount) +{ + ecount_ = ecount; + next = 0; +} + +evctl_real::evctl_real(struct __vpiHandle*handle, double value, + unsigned long ecount) +:evctl(ecount) +{ + handle_ = handle; + value_ = value; +} + +bool evctl_real::dec_and_run() +{ + assert(ecount_ != 0); + + ecount_ -= 1; + + if (ecount_ == 0) { + t_vpi_value val; + + val.format = vpiRealVal; + val.value.real = value_; + vpi_put_value(handle_, &val, 0, vpiNoDelay); + } + + return ecount_ == 0; +} + +void schedule_evctl(struct __vpiHandle*handle, double value, + vvp_net_t*event, unsigned long ecount) +{ + // Get the functor we are going to wait on. + waitable_hooks_s*ep = dynamic_cast (event->fun); + assert(ep); + // Now add this call to the end of the event list. + *(ep->last) = new evctl_real(handle, value, ecount); + ep->last = &((*(ep->last))->next); +} + inline vvp_fun_edge::edge_t VVP_EDGE(vvp_bit4_t from, vvp_bit4_t to) { return 1 << ((from << 2) | to); @@ -270,43 +323,3 @@ void compile_named_event(char*label, char*name) free(label); free(name); } - -/* - * $Log: event.cc,v $ - * Revision 1.23 2006/12/09 19:06:53 steve - * Handle vpiRealVal reads of signals, and real anyedge events. - * - * Revision 1.22 2006/11/22 06:10:05 steve - * Fix spurious event from net8 that is forced. - * - * Revision 1.21 2006/02/21 04:57:26 steve - * Callbacks for named event triggers. - * - * Revision 1.20 2005/06/22 00:04:49 steve - * Reduce vvp_vector4 copies by using const references. - * - * Revision 1.19 2005/06/17 23:47:02 steve - * threads member for waitable_hook_s needs initailizing. - * - * Revision 1.18 2005/05/25 05:44:51 steve - * Handle event/or with specific, efficient nodes. - * - * Revision 1.17 2004/12/29 23:45:13 steve - * Add the part concatenation node (.concat). - * - * Add a vvp_event_anyedge class to handle the special - * case of .event statements of edge type. This also - * frees the posedge/negedge types to handle all 4 inputs. - * - * Implement table functor recv_vec4 method to receive - * and process vectors. - * - * Revision 1.16 2004/12/18 18:52:44 steve - * Rework named events and event/or. - * - * Revision 1.15 2004/12/11 02:31:29 steve - * Rework of internals to carry vectors through nexus instead - * of single bits. Make the ivl, tgt-vvp and vvp initial changes - * down this path. - * - */ diff --git a/vvp/event.h b/vvp/event.h index 7f21d1536..0cea1a184 100644 --- a/vvp/event.h +++ b/vvp/event.h @@ -1,7 +1,7 @@ #ifndef __event_H #define __event_H /* - * Copyright (c) 2004 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-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 @@ -18,13 +18,38 @@ * 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: event.h,v 1.13 2006/12/09 19:06:53 steve Exp $" -#endif # include "vvp_net.h" # include "pointers.h" +class evctl { + + public: + explicit evctl(unsigned long ecount); + virtual bool dec_and_run() = 0; + virtual ~evctl() {} + evctl*next; + + protected: + unsigned long ecount_; +}; + +class evctl_real : public evctl { + + public: + explicit evctl_real(struct __vpiHandle*handle, double value, + unsigned long ecount); + virtual ~evctl_real() {} + bool dec_and_run(); + + private: + __vpiHandle*handle_; + double value_; +}; + +extern void schedule_evctl(struct __vpiHandle*handle, double value, + vvp_net_t*event, unsigned long ecount); + /* * Event / edge detection functors */ @@ -36,8 +61,10 @@ struct waitable_hooks_s { public: - waitable_hooks_s() : threads(0) { } + waitable_hooks_s() : threads(0), event_ctls(0) { last = &event_ctls; } vthread_t threads; + evctl*event_ctls; + evctl**last; protected: void run_waiting_threads_(); @@ -126,40 +153,4 @@ class vvp_named_event : public vvp_net_fun_t, public waitable_hooks_s { struct __vpiHandle*handle_; }; - -/* - * $Log: event.h,v $ - * Revision 1.13 2006/12/09 19:06:53 steve - * Handle vpiRealVal reads of signals, and real anyedge events. - * - * Revision 1.12 2006/11/22 06:10:05 steve - * Fix spurious event from net8 that is forced. - * - * Revision 1.11 2005/06/22 00:04:49 steve - * Reduce vvp_vector4 copies by using const references. - * - * Revision 1.10 2005/06/17 23:47:02 steve - * threads member for waitable_hook_s needs initailizing. - * - * Revision 1.9 2005/05/25 05:44:51 steve - * Handle event/or with specific, efficient nodes. - * - * Revision 1.8 2004/12/29 23:45:13 steve - * Add the part concatenation node (.concat). - * - * Add a vvp_event_anyedge class to handle the special - * case of .event statements of edge type. This also - * frees the posedge/negedge types to handle all 4 inputs. - * - * Implement table functor recv_vec4 method to receive - * and process vectors. - * - * Revision 1.7 2004/12/18 18:52:44 steve - * Rework named events and event/or. - * - * Revision 1.6 2004/12/11 02:31:29 steve - * Rework of internals to carry vectors through nexus instead - * of single bits. Make the ivl, tgt-vvp and vvp initial changes - * down this path. - */ #endif // __event_H diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index 556c0cb27..b7b117fc6 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -105,6 +105,7 @@ vector is to be written. This allows for part writes into the vector. * %assign/wr , , * %assign/wr/d , , +* %assign/wr/e , This instruction provides a non-blocking assign of the real value given in to the real object addressed by the @@ -113,6 +114,10 @@ label after the given . The %assign/wr/d variation gets the delay from integer register . +The %assign/wr/e variation uses the information in the thread +event control registers to determine when to perform the assign. +%evctl is used to set the event control information. + * %assign/x0 , , (OBSOLETE -- See %assign/v0x) This does a non-blocking assignment to a functor, similar to the @@ -296,6 +301,18 @@ This opcode divides the left operand by the right operand. If the right operand is 0, then the result is NaN. +* %evctl +* %evctl/s +* %evctl/i + +These instructions are used to put event and repetition information +into the thread event control registers. These values are then used +by the %assign/e instructions to do not blocking event control. The + is the event to trigger on and the is an index +register to read the repetition count from (signed or unsigned). +%evctl/i sets the repetition to an immediate unsigned value. + + * %force/v