diff --git a/elab_net.cc b/elab_net.cc index 733768c46..ae00cd093 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -1107,8 +1107,20 @@ NetNet*PEIdent::elaborate_unpacked_net(Design*des, NetScope*scope) const perm_string method_name; symbol_search(this, des, scope, path_, sig, par, eve); + if (!sig) { + cerr << get_fileline() << ": error: Net " << path_ + << " is not defined in this context." << endl; + des->errors += 1; + return nullptr; + } - ivl_assert(*this, sig); + const name_component_t&name_tail = path_.back(); + if (name_tail.index.size() != 0) { + cerr << get_fileline() << ": sorry: Array slices are not yet " + << "supported for continuous assignment." << endl; + des->errors += 1; + return nullptr; + } return sig; } diff --git a/elaborate.cc b/elaborate.cc index dfd1fb7d2..052d0d92b 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -260,16 +260,64 @@ void PGAssign::elaborate(Design*des, NetScope*scope) const } +NetNet *elaborate_unpacked_array(Design *des, NetScope *scope, const LineInfo &loc, + const NetNet *lval, PExpr *expr) +{ + PEIdent* ident = dynamic_cast (expr); + if (!ident) { + des->errors++; + if (dynamic_cast (expr)) { + cout << loc.get_fileline() << ": sorry: Continuous assignment" + << " of array concatenation is not yet supported." + << endl; + } else if (dynamic_cast (expr)) { + cout << loc.get_fileline() << ": sorry: Continuous assignment" + << " of assignment pattern is not yet supported." << endl; + } else { + cout << loc.get_fileline() << ": error: Can not assign" + << " non-array expression `" << *expr << "` to array." + << endl; + } + return nullptr; + } + + NetNet *expr_net = ident->elaborate_unpacked_net(des, scope); + if (!expr_net) + return nullptr; + + auto const &lval_dims = lval->unpacked_dims(); + auto const &expr_dims = expr_net->unpacked_dims(); + + if (expr_dims.empty()) { + cerr << loc.get_fileline() << ": error: Can not assign" + << " non-array identifier `" << *expr << "` to array." + << endl; + des->errors++; + return nullptr; + } + + if (!netrange_equivalent(lval_dims, expr_dims)) { + cerr << loc.get_fileline() << ": error: Unpacked dimensions" + << " are not compatible in array assignment." << endl; + des->errors++; + return nullptr; + } + + if (!lval->net_type()->type_equivalent(expr_net->net_type())) { + cerr << loc.get_fileline() << ": error: Element types are not" + << " compatible in array assignment." << endl; + des->errors++; + return nullptr; + } + + return expr_net; +} + void PGAssign::elaborate_unpacked_array_(Design*des, NetScope*scope, NetNet*lval) const { - PEIdent*rval_pident = dynamic_cast (pin(1)); - ivl_assert(*this, rval_pident); - - NetNet*rval_net = rval_pident->elaborate_unpacked_net(des, scope); - - ivl_assert(*this, rval_net->pin_count() == lval->pin_count()); - - assign_unpacked_with_bufz(des, scope, this, lval, rval_net); + NetNet *rval_net = elaborate_unpacked_array(des, scope, *this, lval, pin(1)); + if (rval_net) + assign_unpacked_with_bufz(des, scope, lval, lval, rval_net); } void PGBuiltin::calculate_gate_and_lval_count_(unsigned&gate_count, @@ -1147,6 +1195,29 @@ static void isolate_and_connect(Design*des, NetScope*scope, const PGModule*mod, } } +void elaborate_unpacked_port(Design *des, NetScope *scope, NetNet *port_net, + PExpr *expr, NetNet::PortType port_type, + Module *mod, unsigned int port_idx) +{ + NetNet *expr_net = elaborate_unpacked_array(des, scope, *expr, port_net, + expr); + if (!expr_net) { + perm_string port_name = mod->get_port_name(port_idx); + cerr << expr->get_fileline() << ": : Port " + << port_idx+1 << " (" << port_name << ") of " + << mod->mod_name() << " is connected to " + << *expr << endl; + + return; + } + + ivl_assert(*port_net, expr_net->pin_count() == port_net->pin_count()); + if (port_type == NetNet::POUTPUT) + assign_unpacked_with_bufz(des, scope, port_net, expr_net, port_net); + else + assign_unpacked_with_bufz(des, scope, port_net, port_net, expr_net); +} + /* * Instantiate a module by recursively elaborating it. Set the path of * the recursive elaboration so that signal names get properly @@ -1481,13 +1552,8 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const // differently. if (prts.size() >= 1 && prts[0]->pin_count()>1) { ivl_assert(*this, prts.size()==1); - - PEIdent*rval_pident = dynamic_cast (pins[idx]); - ivl_assert(*this, rval_pident); - - NetNet*rval_net = rval_pident->elaborate_unpacked_net(des, scope); - ivl_assert(*this, rval_net->pin_count() == prts[0]->pin_count()); - assign_unpacked_with_bufz(des, scope, this, prts[0], rval_net); + elaborate_unpacked_port(des, scope, prts[0], pins[idx], + ptype, rmod, idx); continue; } @@ -1650,15 +1716,8 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const // "r-value" expression, but since this is an // output port, we assign to it from the internal object. if (prts[0]->pin_count() > 1) { - ivl_assert(*this, prts.size()==1); - - PEIdent*rval_pident = dynamic_cast(pins[idx]); - ivl_assert(*this, rval_pident); - - NetNet*rval_net = rval_pident->elaborate_unpacked_net(des, scope); - ivl_assert(*this, rval_net->pin_count() == prts[0]->pin_count()); - - assign_unpacked_with_bufz(des, scope, this, rval_net, prts[0]); + elaborate_unpacked_port(des, scope, prts[0], pins[idx], + ptype, rmod, idx); continue; } diff --git a/netparray.cc b/netparray.cc index 3e6e81050..df972f7e3 100644 --- a/netparray.cc +++ b/netparray.cc @@ -86,3 +86,15 @@ vector netuarray_t::slice_dimensions() const { return static_dimensions(); } + +bool netuarray_t::test_equivalence(ivl_type_t that) const +{ + const netuarray_t *that_a = dynamic_cast(that); + if (!that_a) + return false; + + if (!netrange_equivalent(static_dimensions(), that_a->static_dimensions())) + return false; + + return element_type()->type_equivalent(that_a->element_type()); +} diff --git a/netparray.h b/netparray.h index 2e51bf80d..cb122e5b4 100644 --- a/netparray.h +++ b/netparray.h @@ -92,6 +92,9 @@ class netuarray_t : public netsarray_t { public: // Virtual methods from the ivl_type_s type... std::vector slice_dimensions() const; + + private: + bool test_equivalence(ivl_type_t that) const; }; inline netuarray_t::netuarray_t(const std::vector&pd, diff --git a/nettypes.cc b/nettypes.cc index ad2fe5860..5efb8ab63 100644 --- a/nettypes.cc +++ b/nettypes.cc @@ -109,6 +109,20 @@ unsigned long netrange_width(const vector&packed) return wid; } +bool netrange_equivalent(const std::vector &a, + const std::vector &b) +{ + if (a.size() != b.size()) + return false; + + for (size_t i = 0; i < a.size(); i++) { + if (!a[i].equivalent(b[i])) + return false; + } + + return true; +} + /* * Given a netrange_t list (which represent packed dimensions) and a * prefix of calculated index values, calculate the canonical offset diff --git a/nettypes.h b/nettypes.h index dc95eef46..0f0d57958 100644 --- a/nettypes.h +++ b/nettypes.h @@ -137,6 +137,10 @@ class netrange_t { return false; } + bool equivalent(const netrange_t &that) const { + return width() == that.width(); + } + private: long msb_; long lsb_; @@ -146,6 +150,8 @@ extern std::ostream&operator << (std::ostream&out, const std::list&r extern std::ostream&operator << (std::ostream&out, const std::vector&rlist); extern unsigned long netrange_width(const std::vector&dims); +extern bool netrange_equivalent(const std::vector &a, + const std::vector &b); /* * There are a few cases where we need to know about the single-level