Skip to content
Browse files

Fix for pr3194155.

Currently the compiler coerces input ports to inout ports whenever
there is an internal driver connected to the internal port net.
This generates an error if the port is externally connected to
something other than a structural net. This patch modifies the
compiler to ensure port coercion only occurs in valid cases.
  • Loading branch information...
1 parent 2176212 commit e01358babb755d50024c18fb545f1d7db24da581 @martinwhitaker martinwhitaker committed with
Showing with 87 additions and 19 deletions.
  1. +5 −0 PExpr.cc
  2. +9 −0 PExpr.h
  3. +64 −19 elab_net.cc
  4. +9 −0 elaborate.cc
View
5 PExpr.cc
@@ -71,6 +71,11 @@ NetNet* PExpr::elaborate_bi_net(Design*, NetScope*) const
return 0;
}
+bool PExpr::is_collapsible_net(Design*, NetScope*) const
+{
+ return false;
+}
+
PEBinary::PEBinary(char op, PExpr*l, PExpr*r)
: op_(op), left_(l), right_(r)
{
View
9 PExpr.h
@@ -148,6 +148,12 @@ class PExpr : public LineInfo {
// evaluated, return 0.
virtual verinum* eval_const(Design*des, NetScope*sc) const;
+ // This method returns true if the expression represents a
+ // structural net that can have multiple drivers. This is
+ // used to test whether an input port connection can be
+ // collapsed to a single wire.
+ virtual bool is_collapsible_net(Design*des, NetScope*scope) const;
+
// This method returns true if that expression is the same as
// this expression. This method is used for comparing
// expressions that must be structurally "identical".
@@ -193,6 +199,7 @@ class PEConcat : public PExpr {
virtual NetAssign_* elaborate_lval(Design*des,
NetScope*scope,
bool is_force) const;
+ virtual bool is_collapsible_net(Design*des, NetScope*scope) const;
private:
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
bool bidirectional_flag) const;
@@ -302,6 +309,8 @@ class PEIdent : public PExpr {
verinum* eval_const(Design*des, NetScope*sc) const;
+ virtual bool is_collapsible_net(Design*des, NetScope*scope) const;
+
const pform_name_t& path() const { return path_; }
private:
View
83 elab_net.cc
@@ -73,15 +73,17 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
nets[idx] = parms_[idx]->elaborate_lnet(des, scope);
}
- if (nets[idx] == 0) errors += 1;
- else if (nets[idx]->data_type() == IVL_VT_REAL) {
+ if (nets[idx] == 0) {
+ errors += 1;
+ } else if (nets[idx]->data_type() == IVL_VT_REAL) {
cerr << parms_[idx]->get_fileline() << ": error: "
<< "concatenation operand can no be real: "
<< *parms_[idx] << endl;
errors += 1;
continue;
- } else width += nets[idx]->vector_width();
-
+ } else {
+ width += nets[idx]->vector_width();
+ }
}
if (errors) {
@@ -165,6 +167,28 @@ NetNet* PEConcat::elaborate_bi_net(Design*des, NetScope*scope) const
return elaborate_lnet_common_(des, scope, true);
}
+bool PEConcat::is_collapsible_net(Design*des, NetScope*scope) const
+{
+ assert(scope);
+
+ // Repeat concatenations are not currently supported.
+ if (repeat_)
+ return false;
+
+ // Test the operands of the concatenation.
+ for (unsigned idx = 0 ; idx < parms_.size() ; idx += 1) {
+
+ // Empty expressions are not allowed in concatenations
+ if (parms_[idx] == 0)
+ return false;
+
+ if (!parms_[idx]->is_collapsible_net(des, scope))
+ return false;
+ }
+
+ return true;
+}
+
/*
* This private method evaluates the part selects (if any) for the
* signal. The sig argument is the NetNet already located for the
@@ -428,21 +452,6 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
return 0;
}
- if (sig->port_type() == NetNet::PINPUT) {
- sig->port_type(NetNet::PINOUT);
- // This map mask prevents an error message being
- // repeated endlessly.
- static map<string,bool> mask_map;
- bool&flag = mask_map[sig->get_fileline() + ":" + string(sig->name())];
- if (! flag) {
- cerr << get_fileline() << ": warning: L-value ``"
- << sig->name() << "'' is also an input port." << endl;
- cerr << sig->get_fileline() << ": warning: input "
- << sig->name() << "; is coerced to inout." << endl;
- flag = true;
- }
- }
-
// Default part select is the entire word.
unsigned midx = sig->vector_width()-1, lidx = 0;
// The default word select is the first.
@@ -739,3 +748,39 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
scope->add_module_port(sig);
return sig;
}
+
+bool PEIdent::is_collapsible_net(Design*des, NetScope*scope) const
+{
+ assert(scope);
+
+ NetNet* sig = 0;
+ const NetExpr*par = 0;
+ NetEvent* eve = 0;
+
+ symbol_search(this, des, scope, path_, sig, par, eve);
+
+ if (eve != 0)
+ return false;
+
+ if (sig == 0)
+ return false;
+
+ assert(sig);
+
+ /* If this is SystemVerilog and the variable is not yet
+ assigned by anything, then convert it to an unresolved
+ wire. */
+ if (gn_var_can_be_uwire()
+ && (sig->type() == NetNet::REG)
+ && (sig->peek_eref() == 0) ) {
+ sig->type(NetNet::UNRESOLVED_WIRE);
+ }
+
+ if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->pin(0).is_linked())
+ return false;
+
+ if (sig->type() == NetNet::REG)
+ return false;
+
+ return true;
+}
View
9 elaborate.cc
@@ -1306,6 +1306,15 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
if (instance.size() != 1)
desired_vector_width = 0;
+ if (!prts.empty() && (prts[0]->port_type() == NetNet::PINPUT)
+ && prts[0]->pin(0).nexus()->drivers_present()
+ && pins[idx]->is_collapsible_net(des, scope)) {
+ prts[0]->port_type(NetNet::PINOUT);
+
+ cerr << pins[idx]->get_fileline() << ": warning: input port "
+ << prts[0]->name() << " is coerced to inout." << endl;
+ }
+
// Elaborate the expression that connects to the
// module[s] port. sig is the thing outside the module
// that connects to the port.

0 comments on commit e01358b

Please sign in to comment.
Something went wrong with that request. Please try again.