Implement bi-directional part selects.

This commit is contained in:
steve 2005-08-06 17:58:16 +00:00
parent 8232b621f1
commit 4a8be3db9c
12 changed files with 400 additions and 95 deletions

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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