Fix for pr3194155 (v0.9).

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:50:49 +00:00 committed by Stephen Williams
parent 9084c4aab1
commit b1b54ff531
4 changed files with 77 additions and 14 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2008 Stephen Williams <steve@icarus.com>
* Copyright (c) 1998-2008,2011 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
@ -61,6 +61,11 @@ NetNet* PExpr::elaborate_bi_net(Design*des, 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)
{

11
PExpr.h
View File

@ -1,7 +1,7 @@
#ifndef __PExpr_H
#define __PExpr_H
/*
* Copyright (c) 1998-2010 Stephen Williams <steve@icarus.com>
* Copyright (c) 1998-2011 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
@ -133,6 +133,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".
@ -175,6 +181,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;
@ -286,6 +293,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_.count() ; 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;
}
/*
* A private method to create an implicit net.
*/
@ -435,14 +459,6 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
return 0;
}
if (sig->port_type() == NetNet::PINPUT) {
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;
sig->port_type(NetNet::PINOUT);
}
// Default part select is the entire word.
unsigned midx = sig->vector_width()-1, lidx = 0;
// The default word select is the first.
@ -740,3 +756,27 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
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 (sig->type() == NetNet::REG)
return false;
return true;
}

View File

@ -1229,6 +1229,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.