Implement bi-directional part selects.
This commit is contained in:
parent
8232b621f1
commit
4a8be3db9c
|
|
@ -16,7 +16,7 @@
|
|||
# 59 Temple Place - Suite 330
|
||||
# Boston, MA 02111-1307, USA
|
||||
#
|
||||
#ident "$Id: Makefile.in,v 1.172 2005/07/14 23:38:43 steve Exp $"
|
||||
#ident "$Id: Makefile.in,v 1.173 2005/08/06 17:58:16 steve Exp $"
|
||||
#
|
||||
#
|
||||
SHELL = /bin/sh
|
||||
|
|
@ -108,7 +108,7 @@ TT = t-dll.o t-dll-api.o t-dll-expr.o t-dll-proc.o
|
|||
FF = cprop.o nodangle.o synth.o synth2.o syn-rules.o
|
||||
|
||||
O = main.o async.o design_dump.o dup_expr.o elaborate.o elab_expr.o \
|
||||
elab_lval.o elab_net.o elab_anet.o elab_pexpr.o elab_scope.o \
|
||||
elab_lval.o elab_net.o elab_pexpr.o elab_scope.o \
|
||||
elab_sig.o emit.o eval.o eval_attrib.o \
|
||||
eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \
|
||||
load_module.o netlist.o netmisc.o net_assign.o \
|
||||
|
|
|
|||
13
PExpr.cc
13
PExpr.cc
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: PExpr.cc,v 1.35 2004/10/04 01:10:51 steve Exp $"
|
||||
#ident "$Id: PExpr.cc,v 1.36 2005/08/06 17:58:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -53,6 +53,14 @@ NetNet* PExpr::elaborate_lnet(Design*des, NetScope*, bool) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
NetNet* PExpr::elaborate_bi_net(Design*des, NetScope*) const
|
||||
{
|
||||
cerr << get_line() << ": error: "
|
||||
<< "expression not valid as argument to inout port: "
|
||||
<< *this << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
PEBinary::PEBinary(char op, PExpr*l, PExpr*r)
|
||||
: op_(op), left_(l), right_(r)
|
||||
{
|
||||
|
|
@ -262,6 +270,9 @@ bool PEUnary::is_constant(Module*m) const
|
|||
|
||||
/*
|
||||
* $Log: PExpr.cc,v $
|
||||
* Revision 1.36 2005/08/06 17:58:16 steve
|
||||
* Implement bi-directional part selects.
|
||||
*
|
||||
* Revision 1.35 2004/10/04 01:10:51 steve
|
||||
* Clean up spurious trailing white space.
|
||||
*
|
||||
|
|
|
|||
30
PExpr.h
30
PExpr.h
|
|
@ -19,7 +19,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: PExpr.h,v 1.69 2005/07/07 16:22:49 steve Exp $"
|
||||
#ident "$Id: PExpr.h,v 1.70 2005/08/06 17:58:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include <string>
|
||||
|
|
@ -73,15 +73,17 @@ class PExpr : public LineInfo {
|
|||
Link::strength_t drive1 =Link::STRONG)
|
||||
const;
|
||||
|
||||
// This method elaborates the expression as NetNet objects. It
|
||||
// only allows regs suitable for procedural continuous assignments.
|
||||
virtual NetNet* elaborate_anet(Design*des, NetScope*scope) const;
|
||||
|
||||
// This method elaborates the expression as gates, but
|
||||
// restricted for use as l-values of continuous assignments.
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope,
|
||||
bool implicit_net_ok =false) const;
|
||||
|
||||
// This is similar to elaborate_lnet, except that the
|
||||
// expression is evaluated to be bi-directional. This is
|
||||
// useful for arguments to inout ports of module instances and
|
||||
// ports of tran primitives.
|
||||
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const;
|
||||
|
||||
// Expressions that can be in the l-value of procedural
|
||||
// assignments can be elaborated with this method. If the
|
||||
// is_force flag is true, then the set of valid l-value types
|
||||
|
|
@ -122,10 +124,6 @@ class PEConcat : public PExpr {
|
|||
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
// Concatenated Regs can be on the left of procedural
|
||||
// continuous assignments.
|
||||
virtual NetNet* elaborate_anet(Design*des, NetScope*scope) const;
|
||||
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope,
|
||||
bool implicit_net_ok =false) const;
|
||||
virtual NetNet* elaborate_net(Design*des, NetScope*scope,
|
||||
|
|
@ -220,13 +218,12 @@ class PEIdent : public PExpr {
|
|||
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
// Regs can be on the left of procedural continuous assignments
|
||||
virtual NetNet* elaborate_anet(Design*des, NetScope*scope) const;
|
||||
|
||||
// Identifiers are allowed (with restrictions) is assign l-values.
|
||||
virtual NetNet* elaborate_lnet(Design*des, NetScope*scope,
|
||||
bool implicit_net_ok =false) const;
|
||||
|
||||
virtual NetNet* elaborate_bi_net(Design*des, NetScope*scope) const;
|
||||
|
||||
// Identifiers are also allowed as procedural assignment l-values.
|
||||
virtual NetAssign_* elaborate_lval(Design*des,
|
||||
NetScope*scope,
|
||||
|
|
@ -284,6 +281,12 @@ class PEIdent : public PExpr {
|
|||
NetAssign_* elaborate_mem_lval_(Design*des, NetScope*scope,
|
||||
NetMemory*mem) const;
|
||||
|
||||
NetNet* elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
bool implicit_net_ok,
|
||||
bool bidirectional_flag) const;
|
||||
|
||||
NetNet*make_implicit_net_(Design*des, NetScope*scope) const;
|
||||
|
||||
bool eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
||||
unsigned&midx, unsigned&lidx) const;
|
||||
|
||||
|
|
@ -514,6 +517,9 @@ class PECallFunction : public PExpr {
|
|||
|
||||
/*
|
||||
* $Log: PExpr.h,v $
|
||||
* Revision 1.70 2005/08/06 17:58:16 steve
|
||||
* Implement bi-directional part selects.
|
||||
*
|
||||
* Revision 1.69 2005/07/07 16:22:49 steve
|
||||
* Generalize signals to carry types.
|
||||
*
|
||||
|
|
|
|||
89
elab_net.cc
89
elab_net.cc
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: elab_net.cc,v 1.169 2005/07/15 04:13:25 steve Exp $"
|
||||
#ident "$Id: elab_net.cc,v 1.170 2005/08/06 17:58:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -1815,6 +1815,36 @@ NetNet* PEFNumber::elaborate_net(Design*des, NetScope*scope,
|
|||
return net;
|
||||
}
|
||||
|
||||
/*
|
||||
* A private method to create an implicit net.
|
||||
*/
|
||||
NetNet* PEIdent::make_implicit_net_(Design*des, NetScope*scope) const
|
||||
{
|
||||
NetNet::Type nettype = scope->default_nettype();
|
||||
NetNet*sig = 0;
|
||||
|
||||
if (!error_implicit && nettype!=NetNet::NONE) {
|
||||
sig = new NetNet(scope, lex_strings.make(path_.peek_name(0)),
|
||||
NetNet::IMPLICIT, 1);
|
||||
/* Implicit nets are always scalar logic. */
|
||||
sig->data_type(IVL_VT_LOGIC);
|
||||
|
||||
if (warn_implicit) {
|
||||
cerr << get_line() << ": warning: implicit "
|
||||
"definition of wire logic " << scope->name()
|
||||
<< "." << path_.peek_name(0) << "." << endl;
|
||||
}
|
||||
|
||||
} else {
|
||||
cerr << get_line() << ": error: Net " << path_
|
||||
<< " is not defined in this context." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
||||
/*
|
||||
* This private method evaluates the part selects (if any) for the
|
||||
* signal. The sig argument is the NetNet already located for the
|
||||
|
|
@ -1889,11 +1919,13 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
|
|||
}
|
||||
|
||||
/*
|
||||
* Identifiers in continuous assignment l-values are limited to wires
|
||||
* and that ilk. Detect registers and memories here and report errors.
|
||||
* This is the common code for l-value nets and bi-directional
|
||||
* nets. There is very little that is different between the two cases,
|
||||
* so most of the work for both is done here.
|
||||
*/
|
||||
NetNet* PEIdent::elaborate_lnet(Design*des, NetScope*scope,
|
||||
bool implicit_net_ok) const
|
||||
NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
|
||||
bool implicit_net_ok,
|
||||
bool bidirectional_flag) const
|
||||
{
|
||||
assert(scope);
|
||||
|
||||
|
|
@ -1921,26 +1953,16 @@ NetNet* PEIdent::elaborate_lnet(Design*des, NetScope*scope,
|
|||
}
|
||||
|
||||
if (sig == 0) {
|
||||
NetNet::Type nettype = scope->default_nettype();
|
||||
|
||||
if (implicit_net_ok && !error_implicit && nettype!=NetNet::NONE) {
|
||||
if (implicit_net_ok) {
|
||||
|
||||
sig = new NetNet(scope, lex_strings.make(path_.peek_name(0)),
|
||||
NetNet::IMPLICIT, 1);
|
||||
/* Implicit nets are always scalar logic. */
|
||||
sig->data_type(IVL_VT_LOGIC);
|
||||
|
||||
if (warn_implicit) {
|
||||
cerr << get_line() << ": warning: implicit "
|
||||
"definition of wire " << scope->name()
|
||||
<< "." << path_.peek_name(0) << "." << endl;
|
||||
}
|
||||
sig = make_implicit_net_(des, scope);
|
||||
if (sig == 0)
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
cerr << get_line() << ": error: Net " << path_
|
||||
<< " is not defined in this context." << endl;
|
||||
cerr << get_line() << ": : Do you mean this? wire "
|
||||
<< path_ << " = <expr>;" << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1978,6 +2000,15 @@ NetNet* PEIdent::elaborate_lnet(Design*des, NetScope*scope,
|
|||
original vector. */
|
||||
|
||||
if (subnet_wid != sig->vector_width()) {
|
||||
/* If we are processing a tran or inout, then the
|
||||
partselect is bi-directional. Otherwise, it is a
|
||||
Part-to-Vector select. */
|
||||
NetPartSelect::dir_t part_dir;
|
||||
if (bidirectional_flag)
|
||||
part_dir = NetPartSelect::BI;
|
||||
else
|
||||
part_dir = NetPartSelect::PV;
|
||||
|
||||
if (debug_elaborate)
|
||||
cerr << get_line() << ": debug: "
|
||||
<< "Elaborate lnet part select "
|
||||
|
|
@ -1992,7 +2023,7 @@ NetNet* PEIdent::elaborate_lnet(Design*des, NetScope*scope,
|
|||
subsig->data_type( sig->data_type() );
|
||||
|
||||
NetPartSelect*sub = new NetPartSelect(sig, lidx, subnet_wid,
|
||||
NetPartSelect::PV);
|
||||
part_dir);
|
||||
des->add_node(sub);
|
||||
connect(sub->pin(0), subsig->pin(0));
|
||||
|
||||
|
|
@ -2002,6 +2033,21 @@ NetNet* PEIdent::elaborate_lnet(Design*des, NetScope*scope,
|
|||
return sig;
|
||||
}
|
||||
|
||||
/*
|
||||
* Identifiers in continuous assignment l-values are limited to wires
|
||||
* and that ilk. Detect registers and memories here and report errors.
|
||||
*/
|
||||
NetNet* PEIdent::elaborate_lnet(Design*des, NetScope*scope,
|
||||
bool implicit_net_ok) const
|
||||
{
|
||||
return elaborate_lnet_common_(des, scope, implicit_net_ok, false);
|
||||
}
|
||||
|
||||
NetNet* PEIdent::elaborate_bi_net(Design*des, NetScope*scope) const
|
||||
{
|
||||
return elaborate_lnet_common_(des, scope, true, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is used to elaborate identifiers that are ports to a
|
||||
* scope. The scope is presumed to be that of the module that has the
|
||||
|
|
@ -2581,6 +2627,9 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
|
|||
|
||||
/*
|
||||
* $Log: elab_net.cc,v $
|
||||
* Revision 1.170 2005/08/06 17:58:16 steve
|
||||
* Implement bi-directional part selects.
|
||||
*
|
||||
* Revision 1.169 2005/07/15 04:13:25 steve
|
||||
* Match data type of PV select input/output.
|
||||
*
|
||||
|
|
|
|||
94
elaborate.cc
94
elaborate.cc
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: elaborate.cc,v 1.327 2005/07/15 00:41:09 steve Exp $"
|
||||
#ident "$Id: elaborate.cc,v 1.328 2005/08/06 17:58:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -770,13 +770,77 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
|||
// even multiple of the instance count.
|
||||
assert(prts_vector_width % instance.count() == 0);
|
||||
|
||||
unsigned desired_vector_width = prts_vector_width;
|
||||
if (instance.count() != 1)
|
||||
desired_vector_width = 0;
|
||||
|
||||
// Elaborate the expression that connects to the
|
||||
// module[s] port. sig is the thing outside the module
|
||||
// that connects to the port.
|
||||
|
||||
NetNet*sig;
|
||||
if ((prts.count() >= 1)
|
||||
&& (prts[0]->port_type() != NetNet::PINPUT)) {
|
||||
if ((prts.count() == 0)
|
||||
|| (prts[0]->port_type() == NetNet::PINPUT)) {
|
||||
|
||||
/* Input to module. elaborate the expression to
|
||||
the desired width. If this in an instance
|
||||
array, then let the net determine it's own
|
||||
width. We use that, then, to decide how to hook
|
||||
it up.
|
||||
|
||||
NOTE that this also handles the case that the
|
||||
port is actually empty on the inside. We assume
|
||||
in that case that the port is input. */
|
||||
|
||||
sig = pins[idx]->elaborate_net(des, scope,
|
||||
desired_vector_width,
|
||||
0, 0, 0);
|
||||
if (sig == 0) {
|
||||
cerr << pins[idx]->get_line()
|
||||
<< ": internal error: Port expression "
|
||||
<< "too complicated for elaboration." << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
} else if (prts[0]->port_type() == NetNet::PINOUT) {
|
||||
|
||||
/* Inout to/from module. This is a more
|
||||
complicated case, where the expression must be
|
||||
an lnet, but also an r-value net.
|
||||
|
||||
Normally, this winds up being the same as if we
|
||||
just elaborated as an lnet, as passing a simple
|
||||
identifier elaborates to the same NetNet in
|
||||
both cases so the extra elaboration has no
|
||||
effect. But if the expression passed to the
|
||||
inout port is a part select, aspecial part
|
||||
select must be created that can paqss data in
|
||||
both directions.
|
||||
|
||||
Use the elaborate_bi_net method to handle all
|
||||
the possible cases. */
|
||||
|
||||
sig = pins[idx]->elaborate_bi_net(des, scope);
|
||||
if (sig == 0) {
|
||||
cerr << pins[idx]->get_line() << ": error: "
|
||||
<< "Inout port expression must support "
|
||||
<< "continuous assignment." << endl;
|
||||
cerr << pins[idx]->get_line() << ": : "
|
||||
<< "Port of " << rmod->mod_name()
|
||||
<< " is " << rmod->ports[idx]->name << endl;
|
||||
des->errors += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
/* Port type must be OUTPUT here. */
|
||||
|
||||
/* Output from module. Elaborate the port
|
||||
expression as the l-value of a continuous
|
||||
assignment, as the port will continuous assign
|
||||
into the port. */
|
||||
|
||||
sig = pins[idx]->elaborate_lnet(des, scope, true);
|
||||
if (sig == 0) {
|
||||
|
|
@ -790,25 +854,6 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
|||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* Input to module. elaborate the expression to
|
||||
the desired width. If this in an instance
|
||||
array, then let the net determine it's own
|
||||
width. We use that, then, to decide how to hook
|
||||
it up. */
|
||||
unsigned desired_vector_width = prts_vector_width;
|
||||
if (instance.count() != 1)
|
||||
desired_vector_width = 0;
|
||||
|
||||
sig = pins[idx]->elaborate_net(des, scope,
|
||||
desired_vector_width,
|
||||
0, 0, 0);
|
||||
if (sig == 0) {
|
||||
cerr << pins[idx]->get_line()
|
||||
<< ": internal error: Port expression "
|
||||
<< "too complicated for elaboration." << endl;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
assert(sig);
|
||||
|
|
@ -955,7 +1000,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
|||
break;
|
||||
case NetNet::PINOUT:
|
||||
cerr << get_line() << ": XXXX: "
|
||||
<< "Forgot how to bind input ports!" << endl;
|
||||
<< "Forgot how to bind inout ports!" << endl;
|
||||
des->errors += 1;
|
||||
break;
|
||||
case NetNet::PIMPLICIT:
|
||||
|
|
@ -2974,6 +3019,9 @@ Design* elaborate(list<perm_string>roots)
|
|||
|
||||
/*
|
||||
* $Log: elaborate.cc,v $
|
||||
* Revision 1.328 2005/08/06 17:58:16 steve
|
||||
* Implement bi-directional part selects.
|
||||
*
|
||||
* Revision 1.327 2005/07/15 00:41:09 steve
|
||||
* More debug information.
|
||||
*
|
||||
|
|
|
|||
13
ivl_target.h
13
ivl_target.h
|
|
@ -19,7 +19,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: ivl_target.h,v 1.158 2005/07/11 16:56:50 steve Exp $"
|
||||
#ident "$Id: ivl_target.h,v 1.159 2005/08/06 17:58:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
@ -234,6 +234,7 @@ typedef enum ivl_lpm_type_e {
|
|||
IVL_LPM_MOD = 13,
|
||||
IVL_LPM_MULT = 4,
|
||||
IVL_LPM_MUX = 5,
|
||||
IVL_LPM_PART_BI= 28, /* part select: bi-directional (part on 0) */
|
||||
IVL_LPM_PART_VP= 15, /* part select: vector to part */
|
||||
IVL_LPM_PART_PV= 17, /* part select: part written to vector */
|
||||
IVL_LPM_RE_AND = 20,
|
||||
|
|
@ -891,6 +892,13 @@ extern const char* ivl_udp_name(ivl_udp_t net);
|
|||
* indeed the width of the part, even though it is written to a wider
|
||||
* gate. The target will need to handle this case specially.
|
||||
*
|
||||
* - Bi-directional Part Select (IVL_LPM_PART_BI)
|
||||
* This is not exactly a part select but a bi-directional partial link
|
||||
* of two nexa with different widths. This is used to implement tran
|
||||
* devices and inout ports in certain cases. The device width is the
|
||||
* width of the part. The ivl_lpm_q is the part end, and the
|
||||
* ivl_lpm_data(0) is the non-part end.
|
||||
*
|
||||
* - Comparisons (IVL_LPM_CMP_GT/GE/EQ/NE/EEQ/NEE)
|
||||
* These devices have two inputs, available by the ivl_lpm_data()
|
||||
* function, and one output available by the ivl_lpm_q function. The
|
||||
|
|
@ -1662,6 +1670,9 @@ _END_DECL
|
|||
|
||||
/*
|
||||
* $Log: ivl_target.h,v $
|
||||
* Revision 1.159 2005/08/06 17:58:16 steve
|
||||
* Implement bi-directional part selects.
|
||||
*
|
||||
* Revision 1.158 2005/07/11 16:56:50 steve
|
||||
* Remove NetVariable and ivl_variable_t structures.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: netlist.cc,v 1.246 2005/07/11 16:56:50 steve Exp $"
|
||||
#ident "$Id: netlist.cc,v 1.247 2005/08/06 17:58:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -496,8 +496,8 @@ NetPartSelect::NetPartSelect(NetNet*sig, unsigned off, unsigned wid,
|
|||
pin(1).set_dir(Link::OUTPUT);
|
||||
break;
|
||||
case NetPartSelect::BI:
|
||||
pin(0).set_dir(Link::PASSIVE);
|
||||
pin(1).set_dir(Link::PASSIVE);
|
||||
pin(0).set_dir(Link::OUTPUT);
|
||||
pin(1).set_dir(Link::OUTPUT);
|
||||
break;
|
||||
}
|
||||
pin(0).set_name(perm_string::literal("Part"), 0);
|
||||
|
|
@ -2216,6 +2216,9 @@ const NetProc*NetTaskDef::proc() const
|
|||
|
||||
/*
|
||||
* $Log: netlist.cc,v $
|
||||
* Revision 1.247 2005/08/06 17:58:16 steve
|
||||
* Implement bi-directional part selects.
|
||||
*
|
||||
* Revision 1.246 2005/07/11 16:56:50 steve
|
||||
* Remove NetVariable and ivl_variable_t structures.
|
||||
*
|
||||
|
|
|
|||
11
t-dll-api.cc
11
t-dll-api.cc
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: t-dll-api.cc,v 1.130 2005/07/11 16:56:51 steve Exp $"
|
||||
#ident "$Id: t-dll-api.cc,v 1.131 2005/08/06 17:58:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -713,6 +713,7 @@ extern "C" unsigned ivl_lpm_base(ivl_lpm_t net)
|
|||
switch (net->type) {
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV:
|
||||
case IVL_LPM_PART_BI:
|
||||
return net->u_.part.base;
|
||||
default:
|
||||
assert(0);
|
||||
|
|
@ -840,6 +841,7 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
|
|||
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV:
|
||||
case IVL_LPM_PART_BI:
|
||||
assert(idx <= 1);
|
||||
if (idx == 0)
|
||||
return net->u_.part.a;
|
||||
|
|
@ -1012,6 +1014,7 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
|
|||
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV:
|
||||
case IVL_LPM_PART_BI:
|
||||
assert(idx == 0);
|
||||
return net->u_.part.q;
|
||||
|
||||
|
|
@ -1099,6 +1102,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
|
|||
return 0;
|
||||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV:
|
||||
case IVL_LPM_PART_BI:
|
||||
return net->u_.part.signed_flag;
|
||||
case IVL_LPM_REPEAT:
|
||||
return 0;
|
||||
|
|
@ -1167,6 +1171,8 @@ extern "C" unsigned ivl_lpm_width(ivl_lpm_t net)
|
|||
case IVL_LPM_PART_VP:
|
||||
case IVL_LPM_PART_PV:
|
||||
return net->u_.part.width;
|
||||
case IVL_LPM_PART_BI:
|
||||
return net->u_.part.width;
|
||||
case IVL_LPM_REPEAT:
|
||||
return net->u_.repeat.width;
|
||||
default:
|
||||
|
|
@ -2027,6 +2033,9 @@ extern "C" ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net)
|
|||
|
||||
/*
|
||||
* $Log: t-dll-api.cc,v $
|
||||
* Revision 1.131 2005/08/06 17:58:16 steve
|
||||
* Implement bi-directional part selects.
|
||||
*
|
||||
* Revision 1.130 2005/07/11 16:56:51 steve
|
||||
* Remove NetVariable and ivl_variable_t structures.
|
||||
*
|
||||
|
|
|
|||
39
t-dll.cc
39
t-dll.cc
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: t-dll.cc,v 1.153 2005/07/11 16:56:51 steve Exp $"
|
||||
#ident "$Id: t-dll.cc,v 1.154 2005/08/06 17:58:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -1699,7 +1699,7 @@ bool dll_target::part_select(const NetPartSelect*net)
|
|||
obj->type = IVL_LPM_PART_PV;
|
||||
break;
|
||||
case NetPartSelect::BI:
|
||||
assert(0); // XXXX Not supported yet
|
||||
obj->type = IVL_LPM_PART_BI;
|
||||
break;
|
||||
}
|
||||
obj->name = net->name(); // NetPartSelect names are permallocated.
|
||||
|
|
@ -1707,13 +1707,14 @@ bool dll_target::part_select(const NetPartSelect*net)
|
|||
obj->scope = find_scope(des_, net->scope());
|
||||
assert(obj->scope);
|
||||
|
||||
/* Part selects are always unsigned. */
|
||||
obj->u_.part.signed_flag = 0;
|
||||
|
||||
/* Choose the width of the part select. */
|
||||
obj->u_.part.width = net->width();
|
||||
obj->u_.part.base = net->base();
|
||||
obj->u_.part.signed_flag = 0;
|
||||
obj->u_.part.s = 0;
|
||||
|
||||
const Nexus*nex;
|
||||
|
||||
switch (obj->type) {
|
||||
|
|
@ -1753,12 +1754,39 @@ bool dll_target::part_select(const NetPartSelect*net)
|
|||
obj->u_.part.a = (ivl_nexus_t) nex->t_cookie();
|
||||
break;
|
||||
|
||||
case IVL_LPM_PART_BI:
|
||||
/* For now, handle this exactly the same as a PV */
|
||||
|
||||
/* NetPartSelect:pin(0) is the output pin. */
|
||||
nex = net->pin(0).nexus();
|
||||
assert(nex->t_cookie());
|
||||
|
||||
obj->u_.part.q = (ivl_nexus_t) nex->t_cookie();
|
||||
|
||||
/* NetPartSelect:pin(1) is the input pin. */
|
||||
nex = net->pin(1).nexus();
|
||||
assert(nex->t_cookie());
|
||||
|
||||
obj->u_.part.a = (ivl_nexus_t) nex->t_cookie();
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
nexus_lpm_add(obj->u_.part.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
|
||||
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
|
||||
|
||||
/* If the device is a PART_BI, then the "input" is also a
|
||||
strength aware output, so attach it to the nexus with
|
||||
strong driver. */
|
||||
if (obj->type == IVL_LPM_PART_BI)
|
||||
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
|
||||
else
|
||||
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
|
||||
|
||||
/* The select input is optional. */
|
||||
if (obj->u_.part.s)
|
||||
nexus_lpm_add(obj->u_.part.s, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
|
||||
|
||||
scope_add_lpm(obj->scope, obj);
|
||||
|
||||
|
|
@ -2103,6 +2131,9 @@ extern const struct target tgt_dll = { "dll", &dll_target_obj };
|
|||
|
||||
/*
|
||||
* $Log: t-dll.cc,v $
|
||||
* Revision 1.154 2005/08/06 17:58:16 steve
|
||||
* Implement bi-directional part selects.
|
||||
*
|
||||
* Revision 1.153 2005/07/11 16:56:51 steve
|
||||
* Remove NetVariable and ivl_variable_t structures.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: stub.c,v 1.131 2005/07/14 16:15:13 steve Exp $"
|
||||
#ident "$Id: stub.c,v 1.132 2005/08/06 17:58:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "config.h"
|
||||
|
|
@ -656,6 +656,38 @@ static void show_lpm_part(ivl_lpm_t net)
|
|||
}
|
||||
}
|
||||
|
||||
static void show_lpm_part_bi(ivl_lpm_t net)
|
||||
{
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
unsigned base = ivl_lpm_base(net);
|
||||
ivl_nexus_t port_p = ivl_lpm_q(net,0);
|
||||
ivl_nexus_t port_v = ivl_lpm_data(net,0);
|
||||
|
||||
fprintf(out, " LPM_PART_BI %s: <width=%u, base=%u, signed=%d>\n",
|
||||
ivl_lpm_basename(net), width, base, ivl_lpm_signed(net));
|
||||
fprintf(out, " P: %s\n", ivl_nexus_name(port_p));
|
||||
fprintf(out, " V: %s <width=%u>\n", ivl_nexus_name(port_v),
|
||||
width_of_nexus(port_v));
|
||||
|
||||
|
||||
/* The data(0) port must be large enough for the part select. */
|
||||
if (width_of_nexus(ivl_lpm_data(net,0)) < (width+base)) {
|
||||
fprintf(out, " ERROR: Part select is out of range."
|
||||
" Data nexus width=%u, width+base=%u\n",
|
||||
width_of_nexus(ivl_lpm_data(net,0)), width+base);
|
||||
stub_errors += 1;
|
||||
}
|
||||
|
||||
/* The Q vector must be exactly the width of the part select. */
|
||||
if (width_of_nexus(ivl_lpm_q(net,0)) != width) {
|
||||
fprintf(out, " ERROR: Part select input mistatch."
|
||||
" Nexus width=%u, expect width=%u\n",
|
||||
width_of_nexus(ivl_lpm_q(net,0)), width);
|
||||
stub_errors += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void show_lpm_ram(ivl_lpm_t net)
|
||||
{
|
||||
ivl_nexus_t nex;
|
||||
|
|
@ -938,6 +970,11 @@ static void show_lpm(ivl_lpm_t net)
|
|||
show_lpm_part(net);
|
||||
break;
|
||||
|
||||
/* The BI part select is slightly special. */
|
||||
case IVL_LPM_PART_BI:
|
||||
show_lpm_part_bi(net);
|
||||
break;
|
||||
|
||||
case IVL_LPM_REPEAT:
|
||||
show_lpm_repeat(net);
|
||||
break;
|
||||
|
|
@ -1490,6 +1527,9 @@ int target_design(ivl_design_t des)
|
|||
|
||||
/*
|
||||
* $Log: stub.c,v $
|
||||
* Revision 1.132 2005/08/06 17:58:16 steve
|
||||
* Implement bi-directional part selects.
|
||||
*
|
||||
* Revision 1.131 2005/07/14 16:15:13 steve
|
||||
* Dump function call expression node.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: vvp_priv.h,v 1.31 2005/07/13 04:52:31 steve Exp $"
|
||||
#ident "$Id: vvp_priv.h,v 1.32 2005/08/06 17:58:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvp_config.h"
|
||||
|
|
@ -82,12 +82,16 @@ extern int draw_vpi_rfunc_call(ivl_expr_t exp);
|
|||
* Given a nexus, draw a string that represents the functor output
|
||||
* that feeds the nexus. This function can be used to get the input to
|
||||
* a functor, event, or even a %load in cases where I have the
|
||||
* ivl_nexus_t object.
|
||||
* ivl_nexus_t object. The draw_net_input function will get the string
|
||||
* cached in the nexus, if there is one, or will generate a string and
|
||||
* cache it.
|
||||
*/
|
||||
extern void draw_nexus_input(ivl_nexus_t nex);
|
||||
|
||||
extern const char* draw_net_input(ivl_nexus_t nex);
|
||||
|
||||
/*
|
||||
* This is very similar to draw_net_input, but instead of returning a
|
||||
* pointer to the string, it writes it to the output file.
|
||||
*/
|
||||
extern void draw_input_from_net(ivl_nexus_t nex);
|
||||
|
||||
/*
|
||||
|
|
@ -194,6 +198,9 @@ extern unsigned thread_count;
|
|||
|
||||
/*
|
||||
* $Log: vvp_priv.h,v $
|
||||
* Revision 1.32 2005/08/06 17:58:16 steve
|
||||
* Implement bi-directional part selects.
|
||||
*
|
||||
* Revision 1.31 2005/07/13 04:52:31 steve
|
||||
* Handle functions with real values.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifdef HAVE_CVS_IDENT
|
||||
#ident "$Id: vvp_scope.c,v 1.131 2005/07/11 16:56:51 steve Exp $"
|
||||
#ident "$Id: vvp_scope.c,v 1.132 2005/08/06 17:58:16 steve Exp $"
|
||||
#endif
|
||||
|
||||
# include "vvp_priv.h"
|
||||
|
|
@ -603,9 +603,17 @@ static const char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
|
|||
sprintf(result, "L_%p", lpm);
|
||||
return result;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case IVL_LPM_PART_BI:
|
||||
if (ivl_lpm_q(lpm, 0) == nex) {
|
||||
sprintf(result, "L_%p/P", lpm);
|
||||
return result;
|
||||
} else if (ivl_lpm_data(lpm,0) == nex) {
|
||||
sprintf(result, "L_%p/V", lpm);
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(stderr, "internal error: no input to nexus %s\n",
|
||||
|
|
@ -615,16 +623,18 @@ static const char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
|
|||
}
|
||||
|
||||
/*
|
||||
* This function draws the input to a net. What that means is that it
|
||||
* returns a static string that can be used to represent a resolved
|
||||
* driver to a nexus. If there are multiple drivers to the nexus, then
|
||||
* it writes out the resolver declarations needed to perform strength
|
||||
* resolution.
|
||||
* This function draws the input to a net into a string. What that
|
||||
* means is that it returns a static string that can be used to
|
||||
* represent a resolved driver to a nexus. If there are multiple
|
||||
* drivers to the nexus, then it writes out the resolver declarations
|
||||
* needed to perform strength resolution.
|
||||
*
|
||||
* The string that this returns is bound to the nexus, so the pointer
|
||||
* remains valid.
|
||||
* The string that this returns is malloced, and that means that the
|
||||
* caller must free the string or store it permanently. This function
|
||||
* does *not* check for a previously calculated string. Use the
|
||||
* draw_net_input for the general case.
|
||||
*/
|
||||
const char* draw_net_input(ivl_nexus_t nex)
|
||||
char* draw_net_input_x(ivl_nexus_t nex, ivl_nexus_ptr_t omit)
|
||||
{
|
||||
ivl_signal_type_t res;
|
||||
char result[512];
|
||||
|
|
@ -636,11 +646,7 @@ const char* draw_net_input(ivl_nexus_t nex)
|
|||
|
||||
const char*resolv_type;
|
||||
|
||||
/* If this nexus already has a label, then its input is
|
||||
already figured out. Just return the existing label. */
|
||||
char*nex_private = (char*)ivl_nexus_get_private(nex);
|
||||
if (nex_private)
|
||||
return nex_private;
|
||||
char*nex_private = 0;
|
||||
|
||||
res = signal_type_of_nexus(nex);
|
||||
switch (res) {
|
||||
|
|
@ -670,6 +676,9 @@ const char* draw_net_input(ivl_nexus_t nex)
|
|||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ivl_nexus_ptr_t nptr = ivl_nexus_ptr(nex, idx);
|
||||
|
||||
if (nptr == omit)
|
||||
continue;
|
||||
|
||||
/* Skip input only pins. */
|
||||
if ((ivl_nexus_ptr_drive0(nptr) == IVL_DR_HiZ)
|
||||
&& (ivl_nexus_ptr_drive1(nptr) == IVL_DR_HiZ))
|
||||
|
|
@ -711,7 +720,6 @@ const char* draw_net_input(ivl_nexus_t nex)
|
|||
}
|
||||
*tmp++ = '>';
|
||||
*tmp = 0;
|
||||
ivl_nexus_set_private(nex, nex_private);
|
||||
return nex_private;
|
||||
}
|
||||
|
||||
|
|
@ -721,7 +729,6 @@ const char* draw_net_input(ivl_nexus_t nex)
|
|||
TRI type nexus. */
|
||||
if (ndrivers == 1 && res == IVL_SIT_TRI) {
|
||||
nex_private = strdup(draw_net_input_drive(nex, drivers[0]));
|
||||
ivl_nexus_set_private(nex, nex_private);
|
||||
return nex_private;
|
||||
}
|
||||
|
||||
|
|
@ -761,22 +768,36 @@ const char* draw_net_input(ivl_nexus_t nex)
|
|||
|
||||
sprintf(result, "RS_%p", nex);
|
||||
nex_private = strdup(result);
|
||||
return nex_private;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a cached description of the nexus input, or create one if this
|
||||
* nexus has not been cached yet. This is a wrapper for the common
|
||||
* case call to draw_net_input_x.
|
||||
*/
|
||||
const char*draw_net_input(ivl_nexus_t nex)
|
||||
{
|
||||
/* If this nexus already has a label, then its input is
|
||||
already figured out. Just return the existing label. */
|
||||
char*nex_private = (char*)ivl_nexus_get_private(nex);
|
||||
if (nex_private)
|
||||
return nex_private;
|
||||
|
||||
nex_private = draw_net_input_x(nex, 0);
|
||||
ivl_nexus_set_private(nex, nex_private);
|
||||
return nex_private;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This function looks at the nexus in search of the net to attach
|
||||
* functor inputs to. Sort the signals in the nexus by name, and
|
||||
* choose the lexically earliest one.
|
||||
* choose the lexically earliest one. This is different from the
|
||||
* draw_net_input in that it also prints the result.
|
||||
*/
|
||||
void draw_input_from_net(ivl_nexus_t nex)
|
||||
{
|
||||
const char*nex_private = (const char*)ivl_nexus_get_private(nex);
|
||||
if (nex_private == 0)
|
||||
nex_private = draw_net_input(nex);
|
||||
const char*nex_private = draw_net_input(nex);
|
||||
assert(nex_private);
|
||||
fprintf(vvp_out, "%s", nex_private);
|
||||
}
|
||||
|
|
@ -1774,6 +1795,68 @@ static void draw_lpm_part_pv(ivl_lpm_t net)
|
|||
fprintf(vvp_out, ", %u, %u, %u;\n", base, width, signal_width);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the drawing of a bi-directional part select. The two ports
|
||||
* are simultaneously input and output. A simple minded connect of the
|
||||
* input to the output causes a functor cycle which will lock into an
|
||||
* X value, so something special is needed.
|
||||
*
|
||||
* NOTE: The inputs of the tran device at this point need to be from
|
||||
* all the drivers of the nexus *except* the tran itself.
|
||||
*/
|
||||
static void draw_lpm_part_bi(ivl_lpm_t net)
|
||||
{
|
||||
unsigned width = ivl_lpm_width(net);
|
||||
unsigned base = ivl_lpm_base(net);
|
||||
unsigned signal_width = width_of_nexus(ivl_lpm_data(net,0));
|
||||
|
||||
unsigned idx;
|
||||
ivl_nexus_t nex;
|
||||
ivl_nexus_ptr_t ptr;
|
||||
|
||||
char*p_str;
|
||||
char*v_str;
|
||||
|
||||
/* It seems implausible that the two inputs of a tran will be
|
||||
connected together. So assert that this is so to simplify
|
||||
the code to look for the nexus_ptr_t objects. */
|
||||
assert(ivl_lpm_q(net,0) != ivl_lpm_data(net,0));
|
||||
|
||||
nex = ivl_lpm_q(net,0);
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ptr = ivl_nexus_ptr(nex, idx);
|
||||
if (ivl_nexus_ptr_lpm(ptr) == net)
|
||||
break;
|
||||
}
|
||||
p_str = draw_net_input_x(nex, ptr);
|
||||
|
||||
nex = ivl_lpm_data(net,0);
|
||||
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
|
||||
ptr = ivl_nexus_ptr(nex, idx);
|
||||
if (ivl_nexus_ptr_lpm(ptr) == net)
|
||||
break;
|
||||
}
|
||||
v_str = draw_net_input_x(nex, ptr);
|
||||
|
||||
/* Pad the part-sized input out to a common width... */
|
||||
fprintf(vvp_out, "L_%p/i .part/pv %s, %u, %u, %u;\n",
|
||||
net, p_str, base, width, signal_width);
|
||||
|
||||
/* Resolve together the two halves of the tran... */
|
||||
fprintf(vvp_out, "L_%p/V .resolv tri, L_%p/i, %s;\n",
|
||||
net, net, v_str);
|
||||
|
||||
/* The full-width side is created by the tran device, all we
|
||||
have left to to is take a part select of that for the
|
||||
smaller output, and this becomes the part select output of
|
||||
the BI device. */
|
||||
fprintf(vvp_out, "L_%p/P .part L_%p/V, %u, %u;\n", net,
|
||||
net, base, width);
|
||||
|
||||
free(p_str);
|
||||
free(v_str);
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw unary reduction devices.
|
||||
*/
|
||||
|
|
@ -1816,6 +1899,10 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
|
|||
draw_lpm_add(net);
|
||||
return;
|
||||
|
||||
case IVL_LPM_PART_BI:
|
||||
draw_lpm_part_bi(net);
|
||||
return;
|
||||
|
||||
case IVL_LPM_PART_VP:
|
||||
draw_lpm_part(net);
|
||||
return;
|
||||
|
|
@ -1994,6 +2081,9 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
|
|||
|
||||
/*
|
||||
* $Log: vvp_scope.c,v $
|
||||
* Revision 1.132 2005/08/06 17:58:16 steve
|
||||
* Implement bi-directional part selects.
|
||||
*
|
||||
* Revision 1.131 2005/07/11 16:56:51 steve
|
||||
* Remove NetVariable and ivl_variable_t structures.
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in New Issue