diff --git a/PExpr.h b/PExpr.h index a1d3ef8d7..5b9ba3610 100644 --- a/PExpr.h +++ b/PExpr.h @@ -66,7 +66,7 @@ class PExpr : public LineInfo { // The expr_type is an output argument that gives the // calculated type for the expression. // - // The unsigned_flag is set to true if the expression is + // The unsized_flag is set to true if the expression is // unsized and therefore expandable. This happens if a // sub-expression is an unsized literal. Some expressions make // special use of that. @@ -156,6 +156,11 @@ class PEConcat : public PExpr { virtual verinum* eval_const(Design*des, NetScope*sc) const; virtual void dump(ostream&) const; + virtual unsigned test_width(Design*des, NetScope*scope, + unsigned min, unsigned lval, + ivl_variable_type_t&expr_type, + bool&unsized_flag); + 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; diff --git a/cprop.cc b/cprop.cc index 56e3a7bf7..6f39cf9e6 100644 --- a/cprop.cc +++ b/cprop.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2005 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-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 @@ -739,7 +739,8 @@ v } } } -static void replace_with_bufif(Design*des, NetMux*obj, NetLogic::TYPE type) +#if 0 +static void replace_with_mos(Design*des, NetMux*obj, NetLogic::TYPE type) { NetScope*scope = obj->scope(); NetLogic*tmp = new NetLogic(obj->scope(), @@ -749,7 +750,7 @@ static void replace_with_bufif(Design*des, NetMux*obj, NetLogic::TYPE type) des->add_node(tmp); connect(obj->pin_Result(), tmp->pin(0)); - connect(obj->pin_Data(type==NetLogic::BUFIF0? 0 : 1), tmp->pin(1)); + connect(obj->pin_Data(type==NetLogic::PMOS? 0 : 1), tmp->pin(1)); if (obj->width() == 1) { /* Special case that the expression is 1 bit @@ -780,10 +781,11 @@ static void replace_with_bufif(Design*des, NetMux*obj, NetLogic::TYPE type) delete obj; } +#endif /* * This detects the case where the mux selects between a value and - * Vz. In this case, replace the device with a bufif with the sel + * Vz. In this case, replace the device with a mos with the sel * input used to enable the output. */ void cprop_functor::lpm_mux(Design*des, NetMux*obj) @@ -793,45 +795,34 @@ void cprop_functor::lpm_mux(Design*des, NetMux*obj) if (obj->sel_width() != 1) return; +#if 0 +/* + * This is slower than the actual MUXZ so we are skipping this for now. + * If we had a half mux functor this could be faster and more compact + * so I'm leaving the code for future reference. + */ /* If the first input is all constant Vz, then replace the - NetMux with an array of BUFIF1 devices, with the enable + NetMux with an array of NMOS devices, with the enable connected to the select input. */ - bool flag = true; - - if (! obj->pin_Data(0).nexus()->drivers_constant()) { - flag = false; - } - - if (flag && obj->pin_Data(0).nexus()->driven_value() != verinum::Vz) { - flag = false; - } - - if (flag) { - replace_with_bufif(des, obj, NetLogic::BUFIF1); + if (obj->pin_Data(0).nexus()->drivers_constant() && + obj->pin_Data(0).nexus()->driven_value() == verinum::Vz) { + replace_with_mos(des, obj, NetLogic::NMOS); count += 1; return; } - /* If instead the second input is all constant Vz, replace the - NetMux with an array of BUFIF0 devices. */ - flag = true; - if (! obj->pin_Data(1).nexus()->drivers_constant()) { - flag = false; - } - - if (flag && obj->pin_Data(1).nexus()->driven_value() != verinum::Vz) { - flag = false; - } - - if (flag) { - replace_with_bufif(des, obj, NetLogic::BUFIF0); + NetMux with an array of PMOS devices. */ + if (obj->pin_Data(1).nexus()->drivers_constant() && + obj->pin_Data(1).nexus()->driven_value() == verinum::Vz) { + replace_with_mos(des, obj, NetLogic::PMOS); count += 1; return; } +#endif /* If the select input is constant, then replace with a BUFZ */ - flag = obj->pin_Sel().nexus()->drivers_constant(); + bool flag = obj->pin_Sel().nexus()->drivers_constant(); verinum::V sel_val = flag? obj->pin_Sel().nexus()->driven_value() : verinum::Vx; if ((sel_val != verinum::Vz) && (sel_val != verinum::Vx)) { NetBUFZ*tmp = new NetBUFZ(obj->scope(), obj->name(), obj->width()); @@ -974,4 +965,3 @@ void cprop(Design*des) cprop_dc_functor dc; des->functor(&dc); } - diff --git a/elab_expr.cc b/elab_expr.cc index d55476893..a21a7eb42 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -112,7 +112,7 @@ NetExpr* PExpr::elaborate_expr(Design*des, NetScope*, int, bool) const unsigned PEBinary::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, - ivl_variable_type_t&expr_type, + ivl_variable_type_t&expr_type__, bool&unsized_flag) { ivl_variable_type_t expr_type_left = IVL_VT_NO_TYPE; @@ -155,7 +155,7 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope, break; case '*': - if (unsized_flag && type_is_vectorable(expr_type)) { + if (unsized_flag && type_is_vectorable(expr_type_)) { unsigned use_wid = wid_left + wid_right; if (use_wid > integer_width) use_wid = integer_width; @@ -191,7 +191,7 @@ unsigned PEBinary::test_width(Design*des, NetScope*scope, else expr_width_ = 1; - expr_type = expr_type_; + expr_type__ = expr_type_; return expr_width_; } @@ -502,7 +502,7 @@ NetExpr* PEBinary::elaborate_expr_base_lshift_(Design*des, } else if (NetEConst*rpc = dynamic_cast (rp)) { long shift = rpc->value().as_long(); - long use_wid = lp->expr_width(); + use_wid = lp->expr_width(); if (expr_wid > 0) use_wid = expr_wid; @@ -734,15 +734,17 @@ NetExpr* PEBinary::elaborate_expr_base_add_(Design*des, } unsigned PEBComp::test_width(Design*, NetScope*,unsigned, unsigned, - ivl_variable_type_t&expr_type, + ivl_variable_type_t&expr_type__, bool&) { - expr_type = IVL_VT_LOGIC; + expr_type_ = IVL_VT_LOGIC; + expr_type__ = expr_type_; + expr_width_ = 1; return 1; } NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope, - int expr_width, bool sys_task_arg) const + int expr_width_dummy, bool sys_task_arg) const { assert(left_); assert(right_); @@ -793,10 +795,10 @@ NetExpr* PEBComp::elaborate_expr(Design*des, NetScope*scope, unsigned PEBShift::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, - ivl_variable_type_t&expr_type, + ivl_variable_type_t&expr_type__, bool&unsized_flag) { - unsigned wid_left = left_->test_width(des,scope,min, 0, expr_type, unsized_flag); + unsigned wid_left = left_->test_width(des,scope,min, 0, expr_type__, unsized_flag); // The right expression is self-determined and has no impact // on the expression size that is generated. @@ -816,7 +818,22 @@ unsigned PEBShift::test_width(Design*des, NetScope*scope, << endl; } - return wid_left; + expr_type_ = expr_type__; + expr_width_ = wid_left; + + // Run a test-width on the shift amount so that its types are + // worked out for elaboration later on. We don't need the + // value now. + ivl_variable_type_t rtype = IVL_VT_NO_TYPE; + bool rflag = false; + unsigned wid_right = right_->test_width(des, scope, 0, 0, rtype, rflag); + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Test width of shift amount of shift expression " + << "returns wid=" << wid_right << ", type=" << rtype + << ", flag=" << rflag << endl; + + return expr_width_; } NetExpr*PEBShift::elaborate_expr(Design*des, NetScope*scope, @@ -839,7 +856,7 @@ NetExpr*PEBShift::elaborate_expr(Design*des, NetScope*scope, unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, unsigned min, unsigned lval, - ivl_variable_type_t&expr_type, + ivl_variable_type_t&expr_type__, bool&unsized_flag) { perm_string name = peek_tail_name(path_); @@ -848,12 +865,15 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, PExpr*expr = parms_[0]; if (expr == 0) return 0; - unsigned wid = expr->test_width(des, scope, min, lval, expr_type, unsized_flag); + + expr_width_ = expr->test_width(des, scope, min, lval, expr_type__, unsized_flag); + expr_type_ = expr_type__; + if (debug_elaborate) cerr << get_fileline() << ": debug: test_width" << " of $signed/$unsigned returns test_width" << " of subexpression." << endl; - return wid; + return expr_width_; } // Run through the arguments of the system function and make @@ -880,7 +900,7 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, expr_type_ = IVL_VT_BOOL; expr_width_= integer_width; - expr_type = expr_type_; + expr_type__ = expr_type_; return expr_width_; } @@ -892,7 +912,7 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, expr_type_ = IVL_VT_BOOL; expr_width_ = 1; - expr_type = expr_type_; + expr_type__ = expr_type_; return expr_width_; } @@ -904,7 +924,7 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, expr_type_ = sfunc_info->type; expr_width_ = sfunc_info->wid; - expr_type = expr_type_; + expr_type__ = expr_type_; if (debug_elaborate) cerr << get_fileline() << ": debug: test_width " @@ -917,11 +937,11 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, unsigned PECallFunction::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, - ivl_variable_type_t&expr_type, + ivl_variable_type_t&expr_type__, bool&unsized_flag) { if (peek_tail_name(path_)[0] == '$') - return test_width_sfunc_(des, scope, min, lval, expr_type, unsized_flag); + return test_width_sfunc_(des, scope, min, lval, expr_type__, unsized_flag); // The width of user defined functions depends only on the // width of the return value. The arguments are entirely @@ -939,17 +959,19 @@ unsigned PECallFunction::test_width(Design*des, NetScope*scope, assert(dscope); if (NetNet*res = dscope->find_signal(dscope->basename())) { - expr_type = res->data_type(); + expr_type_ = res->data_type(); if (debug_elaborate) cerr << get_fileline() << ": debug: test_width " << "of function returns width " << res->vector_width() - << ", type=" << expr_type + << ", type=" << expr_type_ << "." << endl; - if (! type_is_vectorable(expr_type)) + if (! type_is_vectorable(expr_type__)) unsized_flag = true; - return res->vector_width(); + expr_width_ = res->vector_width(); + expr_type__ = expr_type_; + return expr_width_; } ivl_assert(*this, 0); @@ -1265,6 +1287,21 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, return 0; } +unsigned PEConcat::test_width(Design*des, NetScope*scope, + unsigned min, unsigned lval, + ivl_variable_type_t&expr_type__, + bool&unsized_flag) +{ + expr_type_ = IVL_VT_LOGIC; + + if (debug_elaborate) + cerr << get_fileline() << ": debug: CONCAT MISSING TEST_WIDTH!" << endl; + + expr_type__ = expr_type_; + unsized_flag = false; + return 0; +} + // Keep track of the concatenation/repeat depth. static int concat_depth = 0; @@ -1379,14 +1416,14 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope, */ unsigned PEFNumber::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, - ivl_variable_type_t&expr_type, + ivl_variable_type_t&expr_type__, bool&unsized_flag) { expr_type_ = IVL_VT_REAL; expr_width_ = 1; unsized_flag = true; - expr_type = expr_type_; + expr_type__ = expr_type_; return 1; } @@ -1540,7 +1577,7 @@ bool PEIdent::calculate_param_range_(Design*des, NetScope*scope, unsigned PEIdent::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, - ivl_variable_type_t&expr_type, + ivl_variable_type_t&expr_type__, bool&unsized_flag) { NetNet* net = 0; @@ -1551,11 +1588,6 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, symbol_search(des, scope, path_, net, par, eve, ex1, ex2); - if (net != 0) - expr_type_ = net->data_type(); - - expr_type = expr_type; - // If there is a part/bit select expression, then process it // here. This constrains the results no matter what kind the // name is. @@ -1591,14 +1623,18 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, ivl_assert(*this, 0); } - if (use_width != UINT_MAX) - return max(use_width, min); + if (use_width != UINT_MAX) { + expr_type_ = IVL_VT_LOGIC; // Assume bit/parts selects are logic + expr_width_ = max(use_width, min); + expr_type__ = expr_type_; + return expr_width_; + } // The width of a signal expression is the width of the signal. if (net != 0) { expr_type_ = net->data_type(); expr_width_= max(net->vector_width(), (unsigned long)min); - expr_type = expr_type_; + expr_type__ = expr_type_; return expr_width_; } @@ -1607,7 +1643,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, // width is undefined. if (par != 0) { expr_type_ = par->expr_type(); - expr_type = expr_type_; + expr_type__ = expr_type_; if (ex1) { ivl_assert(*this, ex2); const NetEConst*ex1_const = dynamic_cast (ex1); @@ -1624,7 +1660,7 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, } // This is a parameter. If it is sized (meaning it was - // declared with range expresions) then the range + // declared with range expressions) then the range // expressions would have been caught above. So if we // got there there we know this is an unsized constant. expr_width_ = par->expr_width(); @@ -1632,7 +1668,12 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, return expr_width_; } + // Not a net, and not a parameter? Give up on the type, but + // set the width that we collected. + expr_type_ = IVL_VT_NO_TYPE; expr_width_ = min; + + expr_type__ = expr_type_; return min; } @@ -2070,10 +2111,10 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, rb = verinum::V0; } - NetEConst*re = new NetEConst(verinum(rb, 1)); + NetEConst*re2 = new NetEConst(verinum(rb, 1)); delete tmp; delete mtmp; - tmp = re; + tmp = re2; } else { @@ -2487,7 +2528,7 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, unsigned PENumber::test_width(Design*, NetScope*, unsigned min, unsigned lval, - ivl_variable_type_t&expr_type, + ivl_variable_type_t&expr_type__, bool&unsized_flag) { expr_type_ = IVL_VT_LOGIC; @@ -2501,13 +2542,13 @@ unsigned PENumber::test_width(Design*, NetScope*, if (lval > 0 && lval < use_wid) use_wid = lval; - expr_type = expr_type_; + expr_type__ = expr_type_; expr_width_ = use_wid; return use_wid; } NetEConst* PENumber::elaborate_expr(Design*des, NetScope*, - int expr_width, bool) const + int expr_width__, bool) const { assert(value_); verinum tvalue = *value_; @@ -2516,10 +2557,10 @@ NetEConst* PENumber::elaborate_expr(Design*des, NetScope*, // specific size (for example this is part of the r-values of // an assignment) so we pad to the desired width and ignore // the self-determined size. - if (expr_width > 0) { - tvalue = pad_to_width(tvalue, expr_width); - if (tvalue.len() > (unsigned)expr_width) { - verinum tmp (tvalue, expr_width); + if (expr_width__ > 0) { + tvalue = pad_to_width(tvalue, expr_width__); + if (tvalue.len() > (unsigned)expr_width__) { + verinum tmp (tvalue, expr_width__); tmp.has_sign(tvalue.has_sign()); tvalue = tmp; } @@ -2532,19 +2573,20 @@ NetEConst* PENumber::elaborate_expr(Design*des, NetScope*, unsigned PEString::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, - ivl_variable_type_t&expr_type, + ivl_variable_type_t&expr_type__, bool&unsized_flag) { - expr_type = IVL_VT_BOOL; - unsigned use_wid = text_? 8*strlen(text_) : 0; - if (min > use_wid) - use_wid = min; + expr_type_ = IVL_VT_BOOL; + expr_width_ = text_? 8*strlen(text_) : 0; + if (min > expr_width_) + expr_width_ = min; - return use_wid; + expr_type__ = expr_type_; + return expr_width_; } NetEConst* PEString::elaborate_expr(Design*des, NetScope*, - int expr_width, bool) const + int expr_width_dummy, bool) const { NetEConst*tmp = new NetEConst(value()); tmp->set_line(*this); @@ -2553,9 +2595,15 @@ NetEConst* PEString::elaborate_expr(Design*des, NetScope*, unsigned PETernary::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, - ivl_variable_type_t&expr_type, + ivl_variable_type_t&expr_type__, bool&flag) { + // The condition of the ternary is self-determined, but we + // test its width to force its type to be calculated. + ivl_variable_type_t con_type = IVL_VT_NO_TYPE; + bool con_flag = false; + expr_->test_width(des, scope, 0, 0, con_type, con_flag); + ivl_variable_type_t tru_type = IVL_VT_NO_TYPE; unsigned tru_wid = tru_->test_width(des, scope, min, lval, tru_type,flag); @@ -2583,7 +2631,7 @@ unsigned PETernary::test_width(Design*des, NetScope*scope, expr_width_ = max(tru_wid,fal_wid); - expr_type = expr_type_; + expr_type__ = expr_type_; return expr_width_; } @@ -2626,7 +2674,9 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope, cerr << get_fileline() << ": debug: " << "Self-sized ternary chooses wid="<< use_wid << ", type=" << expr_type() + << ", expr=" << *this << endl; + ivl_assert(*this, use_wid > 0); } @@ -2711,22 +2761,31 @@ NetExpr*PETernary::elaborate_expr(Design*des, NetScope*scope, unsigned PEUnary::test_width(Design*des, NetScope*scope, unsigned min, unsigned lval, - ivl_variable_type_t&expr_type, + ivl_variable_type_t&expr_type__, bool&unsized_flag) { switch (op_) { case '!': - case '&': + case '&': // Reduction AND case '|': // Reduction OR case '^': // Reduction XOR case 'A': // Reduction NAND (~&) case 'N': // Reduction NOR (~|) case 'X': // Reduction NXOR (~^) - expr_type = IVL_VT_LOGIC; - return 1; + { + ivl_variable_type_t sub_type = IVL_VT_NO_TYPE; + bool flag = false; + expr_->test_width(des, scope, 0, 0, sub_type, flag); + expr_type_ = sub_type; + ivl_assert(*expr_, expr_type_ != IVL_VT_NO_TYPE); + } + expr_width_ = 1; + + expr_type__ = expr_type_; + return expr_width_; } - unsigned test_wid = expr_->test_width(des, scope, min, lval, expr_type, unsized_flag); + unsigned test_wid = expr_->test_width(des, scope, min, lval, expr_type__, unsized_flag); switch (op_) { // For these operators, the act of padding to the // minimum width can have an important impact on the @@ -2740,6 +2799,8 @@ unsigned PEUnary::test_width(Design*des, NetScope*scope, break; } + expr_type_ = expr_type__; + expr_width_ = test_wid; return test_wid; } @@ -2803,11 +2864,11 @@ NetExpr* PEUnary::elaborate_expr(Design*des, NetScope*scope, tmp->set_line(*this); delete ip; - } else if (NetECReal*ipc = dynamic_cast(ip)) { + } else if (NetECReal*ipr = dynamic_cast(ip)) { /* When taking the - of a real, fold this into the constant value. */ - verireal val = - ipc->value(); + verireal val = - ipr->value(); tmp = new NetECReal(val); tmp->set_line( *ip ); delete ip; diff --git a/elab_net.cc b/elab_net.cc index d4a8923b8..4e0983c30 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -251,6 +251,27 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, lidx = tmpx; } + /* Warn about an indexed part select that is out of range. */ + if (midx >= (long)sig->vector_width() || lidx < 0) { + cerr << get_fileline() << ": warning: Indexed part " + "select " << sig->name(); + if (sig->array_dimensions() > 0) { + cerr << "[]"; + } + cerr << "[" << midx_val; + if (index_tail.sel == index_component_t::SEL_IDX_UP) { + cerr << "+:"; + } else { + cerr << "-:"; + } + cerr << wid << "] is out of range." << endl; + } + + /* This is completely out side the signal so just skip it. */ + if (lidx >= (long)sig->vector_width() || midx < 0) { + return false; + } + break; } @@ -275,16 +296,24 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, des->errors += 1; } - /* Detect a part select out of range. */ + /* Warn about a part select that is out of range. */ if (midx_tmp >= (long)sig->vector_width() || lidx_tmp < 0) { cerr << get_fileline() << ": warning: Part select " - << sig->name() << "[" << msb << ":" - << lsb << "] out of range." << endl; + << sig->name(); + if (sig->array_dimensions() > 0) { + cerr << "[]"; + } + cerr << "[" << msb << ":" << lsb + << "] is out of range." << endl; #if 0 midx_tmp = sig->vector_width() - 1; lidx_tmp = 0; des->errors += 1; #endif + } + /* This is completely out side the signal so just skip it. */ + if (lidx_tmp >= (long)sig->vector_width() || midx_tmp < 0) { + return false; } midx = midx_tmp; @@ -311,7 +340,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, midx = sig->sb_to_idx(mval->as_long()); if (midx >= (long)sig->vector_width()) { cerr << get_fileline() << ": error: Index " << sig->name() - << "[" << mval->as_long() << "] out of range." + << "[" << mval->as_long() << "] is out of range." << endl; des->errors += 1; midx = 0; @@ -428,7 +457,14 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, long midx_tmp, lidx_tmp; if (! eval_part_select_(des, scope, sig, midx_tmp, lidx_tmp)) return 0; - ivl_assert(*this, lidx_tmp >= 0); + + if (lidx_tmp < 0) { + cerr << get_fileline() << ": sorry: part selects " + "straddling the start of signal (" << path_ + << ") are not currently supported." << endl; + des->errors += 1; + return 0; + } midx = midx_tmp; lidx = lidx_tmp; } @@ -437,7 +473,13 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, if (! eval_part_select_(des, scope, sig, midx_tmp, lidx_tmp)) return 0; - ivl_assert(*this, lidx_tmp >= 0); + if (lidx_tmp < 0) { + cerr << get_fileline() << ": sorry: part selects " + "straddling the start of signal (" << path_ + << ") are not currently supported." << endl; + des->errors += 1; + return 0; + } midx = midx_tmp; lidx = lidx_tmp; } diff --git a/elaborate.cc b/elaborate.cc index 36cc88bc6..503b04b54 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -1295,7 +1295,25 @@ v NOTE that this also handles the case that the if ((instance.count() == 1) && (prts_vector_width != sig->vector_width())) { const char *tmp3 = rmod->ports[idx]->name.str(); + bool as_signed = false; + if (tmp3 == 0) tmp3 = "???"; + + switch (prts[0]->port_type()) { + case NetNet::POUTPUT: + as_signed = prts[0]->get_signed(); + break; + case NetNet::PINPUT: + as_signed = sig->get_signed(); + break; + case NetNet::PINOUT: + /* This may not be correct! */ + as_signed = prts[0]->get_signed() && sig->get_signed(); + break; + default: + ivl_assert(*this, 0); + } + cerr << get_fileline() << ": warning: Port " << (idx+1) << " (" << tmp3 << ") of " << type_ << " expects " << prts_vector_width << @@ -1316,21 +1334,21 @@ v NOTE that this also handles the case that the } // Keep the if, but delete the "} else" when fixed. } else if (prts_vector_width > sig->vector_width()) { - cerr << get_fileline() << ": : Padding " - << (prts_vector_width-sig->vector_width()) + cerr << get_fileline() << ": : Padding "; + if (as_signed) cerr << "(signed) "; + cerr << (prts_vector_width-sig->vector_width()) << " high bits of the port." << endl; } else { - cerr << get_fileline() << ": : Padding " - << (sig->vector_width()-prts_vector_width) + cerr << get_fileline() << ": : Padding "; + if (as_signed) cerr << "(signed) "; + cerr << (sig->vector_width()-prts_vector_width) << " high bits of the expression." << endl; } sig = resize_net_to_port_(des, scope, sig, prts_vector_width, - prts[0]->port_type(), - prts[0]->get_signed() && - sig->get_signed()); + prts[0]->port_type(), as_signed); } // Connect the sig expression that is the context of the @@ -2220,6 +2238,16 @@ NetProc* PCondit::elaborate(Design*des, NetScope*scope) const cerr << get_fileline() << ": debug: Elaborate condition statement" << " with conditional: " << *expr_ << endl; + // Run a test-width on the condition so that its types are + // worked out for elaboration later on. + ivl_variable_type_t rtype = IVL_VT_NO_TYPE; + bool rflag = false; + unsigned expr_wid = expr_->test_width(des, scope, 0, 0, rtype, rflag); + if (debug_elaborate) + cerr << get_fileline() << ": debug: Test width of condition expression" + << " returns wid=" << expr_wid << ", type=" << rtype + << ", flag=" << rflag << endl; + // Elaborate and try to evaluate the conditional expression. NetExpr*expr = elab_and_eval(des, scope, expr_, -1); if (expr == 0) { @@ -2232,7 +2260,7 @@ NetProc* PCondit::elaborate(Design*des, NetScope*scope) const // If the condition of the conditional statement is constant, // then look at the value and elaborate either the if statement // or the else statement. I don't need both. If there is no - // else_ statement, the use an empty block as a noop. + // else_ statement, then use an empty block as a noop. if (NetEConst*ce = dynamic_cast(expr)) { verinum val = ce->value(); if (debug_elaborate) { @@ -2432,9 +2460,9 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const NetUTask*cur; - /* Handle tasks with no parameters specially. There is no need - to make a sequential block to hold the generated code. */ - if (nparms() == 0) { + /* Handle non-automatic tasks with no parameters specially. There is + no need to make a sequential block to hold the generated code. */ + if ((nparms() == 0) && !task->is_auto()) { cur = new NetUTask(task); cur->set_line(*this); return cur; @@ -2825,7 +2853,7 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope, assert(expr_[idx]->expr()); /* If the expression is an identifier that matches a - named event, then handle this case all at once at + named event, then handle this case all at once and skip the rest of the expression handling. */ if (PEIdent*id = dynamic_cast(expr_[idx]->expr())) { diff --git a/expr_synth.cc b/expr_synth.cc index 525ad1d36..c1b7196ec 100644 --- a/expr_synth.cc +++ b/expr_synth.cc @@ -254,7 +254,7 @@ NetNet* NetEBComp::synthesize(Design*des, NetScope*scope) // // Note 2: The operand expressions may be signed even if the // sig that comes out of synthesis is unsigned. The $signed() - // function markes the expression but doesn't change the + // function marks the expression but doesn't change the // underlying signals. bool signed_compare = left_->has_sign() && right_->has_sign(); if (debug_elaborate) { @@ -945,7 +945,7 @@ NetNet* NetEUReduce::synthesize(Design*des, NetScope*scope) * for us: * * - Expression elaboration already converted the offset expression into - * cannonical form, so we don't have to worry about that here. + * canonical form, so we don't have to worry about that here. */ NetNet* NetESelect::synthesize(Design *des, NetScope*scope) { diff --git a/parse.y b/parse.y index 99475d19c..0f9d6bbce 100644 --- a/parse.y +++ b/parse.y @@ -2309,9 +2309,9 @@ generate_case_items ; generate_case_item - : expression ':' { pform_generate_case_item(@1, $1); } generate_block + : expression ':' { pform_generate_case_item(@1, $1); } generate_block_opt { pform_endgenerate(); } - | K_default ':' { pform_generate_case_item(@1, 0); } generate_block + | K_default ':' { pform_generate_case_item(@1, 0); } generate_block_opt { pform_endgenerate(); } ; diff --git a/t-dll-expr.cc b/t-dll-expr.cc index 3dbb8d6c9..8e0f43bb7 100644 --- a/t-dll-expr.cc +++ b/t-dll-expr.cc @@ -257,13 +257,13 @@ void dll_target::expr_const(const NetEConst*net) void dll_target::expr_param(const NetEConstParam*net) { - ivl_scope_t scope = find_scope(des_, net->scope()); - ivl_parameter_t par = scope_find_param(scope, net->name()); + ivl_scope_t scop = find_scope(des_, net->scope()); + ivl_parameter_t par = scope_find_param(scop, net->name()); if (par == 0) { cerr << net->get_fileline() << ": internal error: " << "Parameter " << net->name() << " missing from " - << ivl_scope_name(scope) << endl; + << ivl_scope_name(scop) << endl; } assert(par); assert(par->value); diff --git a/t-dll-proc.cc b/t-dll-proc.cc index b3b96973f..f2031fb0b 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -85,7 +85,7 @@ bool dll_target::process(const NetProcTop*net) void dll_target::task_def(const NetScope*net) { - ivl_scope_t scope = lookup_scope_(net); + ivl_scope_t scop = lookup_scope_(net); const NetTaskDef*def = net->task_def(); assert(stmt_cur_ == 0); @@ -94,14 +94,14 @@ void dll_target::task_def(const NetScope*net) def->proc()->emit_proc(this); assert(stmt_cur_); - scope->def = stmt_cur_; + scop->def = stmt_cur_; stmt_cur_ = 0; } bool dll_target::func_def(const NetScope*net) { - ivl_scope_t scope = lookup_scope_(net); + ivl_scope_t scop = lookup_scope_(net); const NetFuncDef*def = net->func_def(); assert(stmt_cur_ == 0); @@ -110,14 +110,14 @@ bool dll_target::func_def(const NetScope*net) def->proc()->emit_proc(this); assert(stmt_cur_); - scope->def = stmt_cur_; + scop->def = stmt_cur_; stmt_cur_ = 0; - scope->ports = def->port_count() + 1; - if (scope->ports > 0) { - scope->port = new ivl_signal_t[scope->ports]; - for (unsigned idx = 1 ; idx < scope->ports ; idx += 1) - scope->port[idx] = find_signal(des_, def->port(idx-1)); + scop->ports = def->port_count() + 1; + if (scop->ports > 0) { + scop->port = new ivl_signal_t[scop->ports]; + for (unsigned idx = 1 ; idx < scop->ports ; idx += 1) + scop->port[idx] = find_signal(des_, def->port(idx-1)); } /* FIXME: the ivl_target API expects port-0 to be the output @@ -126,7 +126,7 @@ bool dll_target::func_def(const NetScope*net) this, but that will break code generators that use this result. */ if (const NetNet*ret_sig = def->return_sig()) { - scope->port[0] = find_signal(des_, ret_sig); + scop->port[0] = find_signal(des_, ret_sig); return true; } diff --git a/t-dll.cc b/t-dll.cc index d41359bbd..c452f4be0 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -469,15 +469,15 @@ ivl_parameter_t dll_target::scope_find_param(ivl_scope_t scope, * ivl_parameter_t objects. This involves saving the name and scanning * the expression value. */ -void dll_target::make_scope_parameters(ivl_scope_t scope, const NetScope*net) +void dll_target::make_scope_parameters(ivl_scope_t scop, const NetScope*net) { - scope->nparam_ = net->parameters.size() + net->localparams.size(); - if (scope->nparam_ == 0) { - scope->param_ = 0; + scop->nparam_ = net->parameters.size() + net->localparams.size(); + if (scop->nparam_ == 0) { + scop->param_ = 0; return; } - scope->param_ = new struct ivl_parameter_s [scope->nparam_]; + scop->param_ = new struct ivl_parameter_s [scop->nparam_]; unsigned idx = 0; typedef map::const_iterator pit_t; @@ -485,10 +485,10 @@ void dll_target::make_scope_parameters(ivl_scope_t scope, const NetScope*net) for (pit_t cur_pit = net->parameters.begin() ; cur_pit != net->parameters.end() ; cur_pit ++) { - assert(idx < scope->nparam_); - ivl_parameter_t cur_par = scope->param_ + idx; + assert(idx < scop->nparam_); + ivl_parameter_t cur_par = scop->param_ + idx; cur_par->basename = (*cur_pit).first; - cur_par->scope = scope; + cur_par->scope = scop; cur_par->file = (*cur_pit).second.get_file(); cur_par->lineno = (*cur_pit).second.get_lineno(); @@ -499,10 +499,10 @@ void dll_target::make_scope_parameters(ivl_scope_t scope, const NetScope*net) for (pit_t cur_pit = net->localparams.begin() ; cur_pit != net->localparams.end() ; cur_pit ++) { - assert(idx < scope->nparam_); - ivl_parameter_t cur_par = scope->param_ + idx; + assert(idx < scop->nparam_); + ivl_parameter_t cur_par = scop->param_ + idx; cur_par->basename = (*cur_pit).first; - cur_par->scope = scope; + cur_par->scope = scop; cur_par->file = (*cur_pit).second.get_file(); cur_par->lineno = (*cur_pit).second.get_lineno(); @@ -530,9 +530,9 @@ void dll_target::make_scope_param_expr(ivl_parameter_t cur_par, NetExpr*etmp) assert(0); } - } else if (const NetECReal*e = dynamic_cast(etmp)) { + } else if (const NetECReal*er = dynamic_cast(etmp)) { - expr_creal(e); + expr_creal(er); assert(expr_); assert(expr_->type_ == IVL_EX_REALNUM); expr_->u_.real_.parameter = cur_par; @@ -550,7 +550,7 @@ void dll_target::make_scope_param_expr(ivl_parameter_t cur_par, NetExpr*etmp) expr_ = 0; } -void dll_target::add_root(ivl_design_s &des_, const NetScope *s) +void dll_target::add_root(ivl_design_s &des__, const NetScope *s) { ivl_scope_t root_ = new struct ivl_scope_s; perm_string name = s->basename(); @@ -577,12 +577,12 @@ void dll_target::add_root(ivl_design_s &des_, const NetScope *s) root_->attr = fill_in_attributes(s); root_->is_auto = 0; - des_.nroots_++; - if (des_.roots_) - des_.roots_ = (ivl_scope_t *)realloc(des_.roots_, des_.nroots_ * sizeof(ivl_scope_t)); + des__.nroots_++; + if (des__.roots_) + des__.roots_ = (ivl_scope_t *)realloc(des__.roots_, des__.nroots_ * sizeof(ivl_scope_t)); else - des_.roots_ = (ivl_scope_t *)malloc(des_.nroots_ * sizeof(ivl_scope_t)); - des_.roots_[des_.nroots_ - 1] = root_; + des__.roots_ = (ivl_scope_t *)malloc(des__.nroots_ * sizeof(ivl_scope_t)); + des__.roots_[des__.nroots_ - 1] = root_; } bool dll_target::start_design(const Design*des) @@ -615,9 +615,9 @@ bool dll_target::start_design(const Design*des) des_.roots_ = NULL; root_scopes = des->find_root_scopes(); - for (list::const_iterator scope = root_scopes.begin(); - scope != root_scopes.end(); scope++) - add_root(des_, *scope); + for (list::const_iterator scop = root_scopes.begin(); + scop != root_scopes.end(); scop++) + add_root(des_, *scop); des_.consts = (ivl_net_const_t*) malloc(sizeof(ivl_net_const_t)); @@ -848,17 +848,17 @@ bool dll_target::bufz(const NetBUFZ*net) /* Attach the logic device to the scope that contains it. */ assert(net->scope()); - ivl_scope_t scope = find_scope(des_, net->scope()); - assert(scope); + ivl_scope_t scop = find_scope(des_, net->scope()); + assert(scop); - obj->scope_ = scope; + obj->scope_ = scop; obj->name_ = net->name(); logic_attributes(obj, net); make_logic_delays_(obj, net); - scope_add_logic(scope, obj); + scope_add_logic(scop, obj); return true; } @@ -867,10 +867,10 @@ void dll_target::event(const NetEvent*net) { struct ivl_event_s *obj = new struct ivl_event_s; - ivl_scope_t scope = find_scope(des_, net->scope()); + ivl_scope_t scop = find_scope(des_, net->scope()); obj->name = net->name(); - obj->scope = scope; - scope_add_event(scope, obj); + obj->scope = scop; + scope_add_event(scop, obj); obj->nany = 0; obj->nneg = 0; @@ -1029,17 +1029,17 @@ void dll_target::logic(const NetLogic*net) } assert(net->scope()); - ivl_scope_t scope = find_scope(des_, net->scope()); - assert(scope); + ivl_scope_t scop = find_scope(des_, net->scope()); + assert(scop); - obj->scope_= scope; + obj->scope_= scop; obj->name_ = net->name(); logic_attributes(obj, net); make_logic_delays_(obj, net); - scope_add_logic(scope, obj); + scope_add_logic(scop, obj); } bool dll_target::tran(const NetTran*net) @@ -1377,10 +1377,10 @@ void dll_target::udp(const NetUDP*net) } assert(net->scope()); - ivl_scope_t scope = find_scope(des_, net->scope()); - assert(scope); + ivl_scope_t scop = find_scope(des_, net->scope()); + assert(scop); - obj->scope_= scope; + obj->scope_= scop; obj->name_ = net->name(); make_logic_delays_(obj, net); @@ -1388,7 +1388,7 @@ void dll_target::udp(const NetUDP*net) obj->nattr = 0; obj->attr = 0; - scope_add_logic(scope, obj); + scope_add_logic(scop, obj); } void dll_target::lpm_abs(const NetAbs*net) @@ -2293,81 +2293,81 @@ void dll_target::net_probe(const NetEvProbe*net) void dll_target::scope(const NetScope*net) { - ivl_scope_t scope; + ivl_scope_t scop; if (net->parent() == 0) { unsigned i; - scope = NULL; - for (i = 0; i < des_.nroots_ && scope == NULL; i++) { + scop = NULL; + for (i = 0; i < des_.nroots_ && scop == NULL; i++) { if (strcmp(des_.roots_[i]->name_, net->basename()) == 0) - scope = des_.roots_[i]; + scop = des_.roots_[i]; } - assert(scope); + assert(scop); } else { perm_string sname = make_scope_name(net->fullname()); - scope = new struct ivl_scope_s; - scope->name_ = sname; - FILE_NAME(scope, net); - scope->child_ = 0; - scope->sibling_ = 0; - scope->parent = find_scope(des_, net->parent()); - assert(scope->parent); - scope->nsigs_ = 0; - scope->sigs_ = 0; - scope->nlog_ = 0; - scope->log_ = 0; - scope->nevent_ = 0; - scope->event_ = 0; - scope->nlpm_ = 0; - scope->lpm_ = 0; - scope->def = 0; - make_scope_parameters(scope, net); - scope->time_precision = net->time_precision(); - scope->time_units = net->time_unit(); - scope->nattr = net->attr_cnt(); - scope->attr = fill_in_attributes(net); - scope->is_auto = net->is_auto(); + scop = new struct ivl_scope_s; + scop->name_ = sname; + FILE_NAME(scop, net); + scop->child_ = 0; + scop->sibling_ = 0; + scop->parent = find_scope(des_, net->parent()); + assert(scop->parent); + scop->nsigs_ = 0; + scop->sigs_ = 0; + scop->nlog_ = 0; + scop->log_ = 0; + scop->nevent_ = 0; + scop->event_ = 0; + scop->nlpm_ = 0; + scop->lpm_ = 0; + scop->def = 0; + make_scope_parameters(scop, net); + scop->time_precision = net->time_precision(); + scop->time_units = net->time_unit(); + scop->nattr = net->attr_cnt(); + scop->attr = fill_in_attributes(net); + scop->is_auto = net->is_auto(); switch (net->type()) { case NetScope::MODULE: - scope->type_ = IVL_SCT_MODULE; - scope->tname_ = net->module_name(); + scop->type_ = IVL_SCT_MODULE; + scop->tname_ = net->module_name(); break; case NetScope::TASK: { const NetTaskDef*def = net->task_def(); if (def == 0) { cerr << "?:?" << ": internal error: " - << "task " << scope->name_ + << "task " << scop->name_ << " has no definition." << endl; } assert(def); - scope->type_ = IVL_SCT_TASK; - scope->tname_ = def->scope()->basename(); + scop->type_ = IVL_SCT_TASK; + scop->tname_ = def->scope()->basename(); break; } case NetScope::FUNC: - scope->type_ = IVL_SCT_FUNCTION; - scope->tname_ = net->func_def()->scope()->basename(); + scop->type_ = IVL_SCT_FUNCTION; + scop->tname_ = net->func_def()->scope()->basename(); break; case NetScope::BEGIN_END: - scope->type_ = IVL_SCT_BEGIN; - scope->tname_ = scope->name_; + scop->type_ = IVL_SCT_BEGIN; + scop->tname_ = scop->name_; break; case NetScope::FORK_JOIN: - scope->type_ = IVL_SCT_FORK; - scope->tname_ = scope->name_; + scop->type_ = IVL_SCT_FORK; + scop->tname_ = scop->name_; break; case NetScope::GENBLOCK: - scope->type_ = IVL_SCT_GENERATE; - scope->tname_ = scope->name_; + scop->type_ = IVL_SCT_GENERATE; + scop->tname_ = scop->name_; break; } - assert(scope->parent != 0); + assert(scop->parent != 0); - scope->sibling_= scope->parent->child_; - scope->parent->child_ = scope; + scop->sibling_= scop->parent->child_; + scop->parent->child_ = scop; } } diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index be7f22f1c..1cf47d03c 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -407,8 +407,8 @@ bits. 5: (reserved) 6: (reserved) -* %ix/getv , -* %ix/getv/s , +* %ix/getv , +* %ix/getv/s , These instructions are like the %ix/get instructions, except that they read directly from a functor label instead of from thread bits. They diff --git a/vvp/resolv.cc b/vvp/resolv.cc index d0db6ec3c..3b779a093 100644 --- a/vvp/resolv.cc +++ b/vvp/resolv.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2007 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-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 @@ -49,7 +49,7 @@ void resolv_functor::recv_vec4_pv(vvp_net_ptr_t port, const vvp_vector4_t&bit, for (unsigned idx = 0 ; idx < base ; idx += 1) res.set_bit(idx, BIT4_Z); - for (unsigned idx = 0 ; idx < wid ; idx += 1) + for (unsigned idx = 0 ; idx < wid && idx+base < vwid; idx += 1) res.set_bit(idx+base, bit.value(idx)); for (unsigned idx = base+wid ; idx < vwid ; idx += 1) @@ -106,7 +106,7 @@ void resolv_functor::recv_vec8_pv(vvp_net_ptr_t port, const vvp_vector8_t&bit, for (unsigned idx = 0 ; idx < base ; idx += 1) res.set_bit(idx, vvp_scalar_t()); - for (unsigned idx = 0 ; idx < wid ; idx += 1) + for (unsigned idx = 0 ; idx < wid && idx+base < vwid; idx += 1) res.set_bit(idx+base, bit.value(idx)); for (unsigned idx = base+wid ; idx < vwid ; idx += 1)