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:
parent
9084c4aab1
commit
b1b54ff531
7
PExpr.cc
7
PExpr.cc
|
|
@ -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
11
PExpr.h
|
|
@ -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:
|
||||
|
|
|
|||
64
elab_net.cc
64
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_.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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue