diff --git a/Makefile.in b/Makefile.in index ffff36e88..5a6ae894d 100644 --- a/Makefile.in +++ b/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 \ diff --git a/PExpr.cc b/PExpr.cc index 3640598c2..75f6dba84 100644 --- a/PExpr.cc +++ b/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. * diff --git a/PExpr.h b/PExpr.h index 8298e1012..f518f67cc 100644 --- a/PExpr.h +++ b/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 @@ -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. * diff --git a/elab_net.cc b/elab_net.cc index 9e7e630f9..96f41e7bc 100644 --- a/elab_net.cc +++ b/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_ << " = ;" << 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. * diff --git a/elaborate.cc b/elaborate.cc index f439fe487..62f70f8a0 100644 --- a/elaborate.cc +++ b/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(listroots) /* * $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. * diff --git a/ivl_target.h b/ivl_target.h index 3efc8e7c4..5c4b883bc 100644 --- a/ivl_target.h +++ b/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. * diff --git a/netlist.cc b/netlist.cc index 9f6772e68..85fc3e6da 100644 --- a/netlist.cc +++ b/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. * diff --git a/t-dll-api.cc b/t-dll-api.cc index 8ba37dd36..581939c71 100644 --- a/t-dll-api.cc +++ b/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. * diff --git a/t-dll.cc b/t-dll.cc index 715ba0cc2..a3580724f 100644 --- a/t-dll.cc +++ b/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. * diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 1a5f9bdbd..2e2188f4f 100644 --- a/tgt-stub/stub.c +++ b/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: \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 \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. * diff --git a/tgt-vvp/vvp_priv.h b/tgt-vvp/vvp_priv.h index 58ac4fd69..8519dcade 100644 --- a/tgt-vvp/vvp_priv.h +++ b/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. * diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 41a7a6983..c6db082a5 100644 --- a/tgt-vvp/vvp_scope.c +++ b/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); + 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. *