Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Implement bi-directional part selects.

  • Loading branch information...
commit 4a8be3db9c6f1a487c0f356d37993a098fe9c05b 1 parent 8232b62
steve authored
View
4 Makefile.in
@@ -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
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.
*
View
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.
*
View
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"
@@ -1816,6 +1816,36 @@ NetNet* PEFNumber::elaborate_net(Design*des, NetScope*scope,
}
/*
+ * 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
* PEIdent name. The midx and lidx arguments are loaded with 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));
@@ -2003,6 +2034,21 @@ NetNet* PEIdent::elaborate_lnet(Design*des, NetScope*scope,
}
/*
+ * 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
* port. This elaboration is done inside the module, and is only done
@@ -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
88 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,18 +770,60 @@ 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)) {
- sig = pins[idx]->elaborate_lnet(des, scope, true);
+ /* 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: "
- << "Output port expression must support "
+ << "Inout port expression must support "
<< "continuous assignment." << endl;
cerr << pins[idx]->get_line() << ": : "
<< "Port of " << rmod->mod_name()
@@ -790,25 +832,28 @@ 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);
+ /* 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) {
- cerr << pins[idx]->get_line()
- << ": internal error: Port expression "
- << "too complicated for elaboration." << endl;
+ cerr << pins[idx]->get_line() << ": error: "
+ << "Output 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;
}
+
}
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
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.
*
View
9 netlist.cc
@@ -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
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.
*
View
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.
*
View
42 tgt-stub/stub.c
@@ -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
15 tgt-vvp/vvp_priv.h
@@ -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
134 tgt-vvp/vvp_scope.c
@@ -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);
- ivl_nexus_set_private(nex, nex_private);
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);
}
@@ -1775,6 +1796,68 @@ static void draw_lpm_part_pv(ivl_lpm_t net)
}
/*
+ * 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.
*/
static void draw_lpm_re(ivl_lpm_t net, const char*type)
@@ -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.
*
Please sign in to comment.
Something went wrong with that request. Please try again.