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.
This commit is contained in:
Martin Whitaker 2011-03-13 13:29:42 +00:00 committed by Stephen Williams
parent 2176212e2b
commit e01358babb
4 changed files with 87 additions and 19 deletions

View File

@ -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 File

@ -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 File

@ -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 File

@ -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.