diff --git a/elab_net.cc b/elab_net.cc index f73b29531..60550ecd6 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.161 2005/05/06 00:25:13 steve Exp $" +#ident "$Id: elab_net.cc,v 1.162 2005/05/08 23:44:08 steve Exp $" #endif # include "config.h" @@ -1434,54 +1434,51 @@ NetNet* PEIdent::elaborate_net_bitmux_(Design*des, NetScope*scope, Link::strength_t drive1) const { /* Elaborate the selector. */ - NetNet*sel = msb_->elaborate_net(des, scope, 0, 0, 0, 0); + NetNet*sel; - unsigned sig_width = sig->pin_count(); + unsigned sig_width = sig->vector_width(); - /* Detect the case of some bits not accessible by the given - select. Figure out how many bits can be selected by the - full range of the select, and limit the input of the mux to - that width. */ - { unsigned max_width_by_sel = 1 << sel->pin_count(); - if (sig_width > max_width_by_sel) - sig_width = max_width_by_sel; - } -#if 0 - NetMux*mux = new NetMux(scope, scope->local_symbol(), 1, - sig_width, sel->pin_count()); + if (sig->msb() < sig->lsb()) { + NetExpr*sel_expr = msb_->elaborate_expr(des, scope); + sel_expr = make_sub_expr(sig->lsb(), sel_expr); + if (NetExpr*tmp = sel_expr->eval_tree()) { + delete sel_expr; + sel_expr = tmp; + } - /* Connect the signal bits to the mux. Account for the - direction of the numbering (lsb to msb vs. msb to lsb) by - swapping the connection order. */ + sel = sel_expr->synthesize(des); - if (sig->msb() > sig->lsb()) { + } else if (sig->lsb() != 0) { + NetExpr*sel_expr = msb_->elaborate_expr(des, scope); + sel_expr = make_add_expr(sel_expr, - sig->lsb()); + if (NetExpr*tmp = sel_expr->eval_tree()) { + delete sel_expr; + sel_expr = tmp; + } + + sel = sel_expr->synthesize(des); - sel = add_to_net(des, sel, -sig->lsb()); - for (unsigned idx = 0 ; idx < sig_width ; idx += 1) - connect(mux->pin_Data(0, idx), sig->pin(idx)); } else { - - sel = add_to_net(des, sel, -sig->msb()); - for (unsigned idx = 0 ; idx < sig_width ; idx += 1) - connect(mux->pin_Data(0, idx), sig->pin(sig_width-idx-1)); + sel = msb_->elaborate_net(des, scope, 0, 0, 0, 0); } - for (unsigned idx = 0 ; idx < sel->pin_count() ; idx += 1) - connect(mux->pin_Sel(idx), sel->pin(idx)); + if (debug_elaborate) { + cerr << get_line() << ": debug: Create NetPartSelect " + << "using signal " << sel->name() << " as selector" + << endl; + } + + /* Create a part select that takes a non-constant offset and a + width of 1. */ + NetPartSelect*mux = new NetPartSelect(sig, sel, 1); + des->add_node(mux); + mux->set_line(*this); NetNet*out = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, 1); - connect(mux->pin_Result(0), out->pin(0)); + NetNet::WIRE, 1); - des->add_node(mux); - out->local_flag(true); + connect(out->pin(0), mux->pin(0)); return out; -#else - cerr << get_line() << ": sorry: Forgot how to implement" - << " NetMux in elaborate_net_bitmux_." << endl; - des->errors += 1; - return 0; -#endif } NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope, @@ -2508,6 +2505,9 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope, /* * $Log: elab_net.cc,v $ + * Revision 1.162 2005/05/08 23:44:08 steve + * Add support for variable part select. + * * Revision 1.161 2005/05/06 00:25:13 steve * Handle synthesis of concatenation expressions. * diff --git a/ivl_target.h b/ivl_target.h index 0b2eab6f5..df548d1ef 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.153 2005/05/07 03:14:00 steve Exp $" +#ident "$Id: ivl_target.h,v 1.154 2005/05/08 23:44:08 steve Exp $" #endif #ifdef __cplusplus @@ -856,11 +856,16 @@ extern const char* ivl_udp_name(ivl_udp_t net); * model part/bin selects in r-value expressions, where the _PV from * is meant to model part selects in l-value nets. * - * In both cases, ivl_lpm_data is the input pin, and ivl_lpm_q is the + * In both cases, ivl_lpm_data(0) is the input pin, and ivl_lpm_q is the * output. In the case of the _VP device, the vector is input and the * part is the output. In the case of the _PV device, the part is the * input and the vector is the output. * + * If the base of the part select is non-constant, then + * ivl_lpm_data(1) is non-nil and is the select, or base, address of + * the part. If this pin is nil, then the constant base is used + * instead. + * * Also in both cases, the width of the device is the width of the * part. In the _VP case, this is obvious as the output nexus has the * part width. In the _PV case, this is a little less obvious, but @@ -1653,6 +1658,9 @@ _END_DECL /* * $Log: ivl_target.h,v $ + * Revision 1.154 2005/05/08 23:44:08 steve + * Add support for variable part select. + * * Revision 1.153 2005/05/07 03:14:00 steve * Clarify internal delays for assignments. * diff --git a/netlist.cc b/netlist.cc index a3bf1ac47..95e8db924 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.242 2005/04/24 23:44:02 steve Exp $" +#ident "$Id: netlist.cc,v 1.243 2005/05/08 23:44:08 steve Exp $" #endif # include "config.h" @@ -490,6 +490,35 @@ NetPartSelect::NetPartSelect(NetNet*sig, unsigned off, unsigned wid, pin(1).set_name(perm_string::literal("Vect"), 0); } +NetPartSelect::NetPartSelect(NetNet*sig, NetNet*sel, + unsigned wid) +: NetNode(sig->scope(), sig->scope()->local_symbol(), 3), + off_(0), wid_(wid), dir_(VP) +{ + connect(pin(1), sig->pin(0)); + connect(pin(2), sel->pin(0)); + + switch (dir_) { + case NetPartSelect::VP: + pin(0).set_dir(Link::OUTPUT); + pin(1).set_dir(Link::INPUT); + break; + case NetPartSelect::PV: + pin(0).set_dir(Link::INPUT); + pin(1).set_dir(Link::OUTPUT); + break; + case NetPartSelect::BI: + pin(0).set_dir(Link::PASSIVE); + pin(1).set_dir(Link::PASSIVE); + break; + } + pin(2).set_dir(Link::INPUT); + + pin(0).set_name(perm_string::literal("Part"), 0); + pin(1).set_name(perm_string::literal("Vect"), 0); + pin(2).set_name(perm_string::literal("Select"), 0); +} + NetPartSelect::~NetPartSelect() { } @@ -2156,6 +2185,9 @@ const NetProc*NetTaskDef::proc() const /* * $Log: netlist.cc,v $ + * Revision 1.243 2005/05/08 23:44:08 steve + * Add support for variable part select. + * * Revision 1.242 2005/04/24 23:44:02 steve * Update DFF support to new data flow. * diff --git a/netlist.h b/netlist.h index c916400cd..5f346c3e1 100644 --- a/netlist.h +++ b/netlist.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: netlist.h,v 1.341 2005/04/24 23:44:02 steve Exp $" +#ident "$Id: netlist.h,v 1.342 2005/05/08 23:44:08 steve Exp $" #endif /* @@ -1193,6 +1193,10 @@ class NetECRealParam : public NetECReal { * The part to be selected is the canonical (0-based) offset and the * specified number of bits (wid). * + * If the offset is non-constant, then pin(2) is the input vector for + * the selector. If this pin is present, then use the non-constant + * selector as the input. + * * The NetPartSelect can be output from the signal (i.e. reading a * part), input into the signal, or bi-directional. The DIR method * gives the type of the node. @@ -1220,6 +1224,8 @@ class NetPartSelect : public NetNode { explicit NetPartSelect(NetNet*sig, unsigned off, unsigned wid, dir_t dir); + explicit NetPartSelect(NetNet*sig, NetNet*sel, + unsigned wid); ~NetPartSelect(); unsigned base() const; @@ -3437,6 +3443,9 @@ extern ostream& operator << (ostream&, NetNet::Type); /* * $Log: netlist.h,v $ + * Revision 1.342 2005/05/08 23:44:08 steve + * Add support for variable part select. + * * Revision 1.341 2005/04/24 23:44:02 steve * Update DFF support to new data flow. * diff --git a/t-dll-api.cc b/t-dll-api.cc index c36fefe5c..5b8059bf8 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.125 2005/04/24 23:44:02 steve Exp $" +#ident "$Id: t-dll-api.cc,v 1.126 2005/05/08 23:44:08 steve Exp $" #endif # include "config.h" @@ -828,8 +828,11 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx) case IVL_LPM_PART_VP: case IVL_LPM_PART_PV: - assert(idx == 0); - return net->u_.part.a; + assert(idx <= 1); + if (idx == 0) + return net->u_.part.a; + else + return net->u_.part.s; case IVL_LPM_REPEAT: assert(idx == 0); @@ -2032,6 +2035,9 @@ extern "C" ivl_variable_type_t ivl_variable_type(ivl_variable_t net) /* * $Log: t-dll-api.cc,v $ + * Revision 1.126 2005/05/08 23:44:08 steve + * Add support for variable part select. + * * Revision 1.125 2005/04/24 23:44:02 steve * Update DFF support to new data flow. * diff --git a/t-dll.cc b/t-dll.cc index 96ca7b1b4..44aa304e0 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.148 2005/04/24 23:44:02 steve Exp $" +#ident "$Id: t-dll.cc,v 1.149 2005/05/08 23:44:08 steve Exp $" #endif # include "config.h" @@ -1720,6 +1720,7 @@ bool dll_target::part_select(const NetPartSelect*net) 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) { @@ -1735,6 +1736,14 @@ bool dll_target::part_select(const NetPartSelect*net) assert(nex->t_cookie()); obj->u_.part.a = (ivl_nexus_t) nex->t_cookie(); + + /* If the part select has an additional pin, that pin is + a variable select base. */ + if (net->pin_count() >= 3) { + nex = net->pin(2).nexus(); + assert(nex->t_cookie()); + obj->u_.part.s = (ivl_nexus_t) nex->t_cookie(); + } break; case IVL_LPM_PART_PV: @@ -2071,6 +2080,9 @@ extern const struct target tgt_dll = { "dll", &dll_target_obj }; /* * $Log: t-dll.cc,v $ + * Revision 1.149 2005/05/08 23:44:08 steve + * Add support for variable part select. + * * Revision 1.148 2005/04/24 23:44:02 steve * Update DFF support to new data flow. * diff --git a/t-dll.h b/t-dll.h index 815a5fa9c..5d528de4d 100644 --- a/t-dll.h +++ b/t-dll.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: t-dll.h,v 1.124 2005/04/01 06:04:30 steve Exp $" +#ident "$Id: t-dll.h,v 1.125 2005/05/08 23:44:08 steve Exp $" #endif # include "target.h" @@ -344,7 +344,7 @@ struct ivl_lpm_s { unsigned width; unsigned base; unsigned signed_flag :1; - ivl_nexus_t q, a; + ivl_nexus_t q, a, s; } part; // IVL_LPM_RE_* and IVL_LPM_REPEAT use this. @@ -685,6 +685,9 @@ struct ivl_variable_s { /* * $Log: t-dll.h,v $ + * Revision 1.125 2005/05/08 23:44:08 steve + * Add support for variable part select. + * * Revision 1.124 2005/04/01 06:04:30 steve * Clean up handle of UDPs. * diff --git a/tgt-stub/statement.c b/tgt-stub/statement.c index 344e067bf..f297ed973 100644 --- a/tgt-stub/statement.c +++ b/tgt-stub/statement.c @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: statement.c,v 1.5 2005/03/05 05:47:42 steve Exp $" +#ident "$Id: statement.c,v 1.6 2005/05/08 23:44:08 steve Exp $" #endif # include "config.h" @@ -190,6 +190,9 @@ void show_statement(ivl_statement_t net, unsigned ind) for (idx = 0 ; idx < ivl_stmt_lvals(net) ; idx += 1) show_assign_lval(ivl_stmt_lval(net, idx), ind+4); + if (ivl_stmt_delay_expr(net)) + show_expression(ivl_stmt_delay_expr(net), idx+4); + if (ivl_stmt_rval(net)) show_expression(ivl_stmt_rval(net), ind+4); break; @@ -201,6 +204,11 @@ void show_statement(ivl_statement_t net, unsigned ind) for (idx = 0 ; idx < ivl_stmt_lvals(net) ; idx += 1) show_assign_lval(ivl_stmt_lval(net, idx), ind+4); + if (ivl_stmt_delay_expr(net)) { + fprintf(out, "%*s\n", ind+4, ""); + show_expression(ivl_stmt_delay_expr(net), ind+6); + } + if (ivl_stmt_rval(net)) show_expression(ivl_stmt_rval(net), ind+4); break; diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 8b4e311db..507dbd2bf 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.123 2005/04/24 23:44:02 steve Exp $" +#ident "$Id: stub.c,v 1.124 2005/05/08 23:44:08 steve Exp $" #endif # include "config.h" @@ -544,6 +544,7 @@ static void show_lpm_part(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); unsigned base = ivl_lpm_base(net); + ivl_nexus_t sel = ivl_lpm_data(net,1); const char*part_type_string = ""; switch (ivl_lpm_type(net)) { @@ -563,6 +564,14 @@ static void show_lpm_part(ivl_lpm_t net) fprintf(out, " O: %s\n", ivl_nexus_name(ivl_lpm_q(net,0))); fprintf(out, " I: %s\n", ivl_nexus_name(ivl_lpm_data(net,0))); + if (sel != 0) { + fprintf(out, " S: %s\n", ivl_nexus_name(sel)); + if (base != 0) { + fprintf(out, " ERROR: Part select has base AND selector\n"); + stub_errors += 1; + } + } + /* The compiler must assure that the base plus the part select width fits within the input to the part select. */ if (width_of_nexus(ivl_lpm_data(net,0)) < (width+base)) { @@ -1353,6 +1362,9 @@ int target_design(ivl_design_t des) /* * $Log: stub.c,v $ + * Revision 1.124 2005/05/08 23:44:08 steve + * Add support for variable part select. + * * Revision 1.123 2005/04/24 23:44:02 steve * Update DFF support to new data flow. * diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 74317d92d..077d6c4ab 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.126 2005/04/24 23:44:02 steve Exp $" +#ident "$Id: vvp_scope.c,v 1.127 2005/05/08 23:44:08 steve Exp $" #endif # include "vvp_priv.h" @@ -1683,19 +1683,29 @@ static void draw_lpm_ufunc(ivl_lpm_t net) } /* - * Handle a PART SELECT device. This has a single input and output. + * Handle a PART SELECT device. This has a single input and output, + * plus an optional extra input that is a non-constant base. */ static void draw_lpm_part(ivl_lpm_t net) { unsigned width, base; + ivl_nexus_t sel; width = ivl_lpm_width(net); base = ivl_lpm_base(net); + sel = ivl_lpm_data(net,1); - fprintf(vvp_out, "L_%p .part ", net); - draw_input_from_net(ivl_lpm_data(net, 0)); - - fprintf(vvp_out, ", %u, %u;\n", base, width); + if (sel == 0) { + fprintf(vvp_out, "L_%p .part ", net); + draw_input_from_net(ivl_lpm_data(net, 0)); + fprintf(vvp_out, ", %u, %u;\n", base, width); + } else { + fprintf(vvp_out, "L_%p .part/v ", net); + draw_input_from_net(ivl_lpm_data(net,0)); + fprintf(vvp_out, ", "); + draw_input_from_net(sel); + fprintf(vvp_out, ", %u;\n", width); + } } /* @@ -1932,6 +1942,9 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) /* * $Log: vvp_scope.c,v $ + * Revision 1.127 2005/05/08 23:44:08 steve + * Add support for variable part select. + * * Revision 1.126 2005/04/24 23:44:02 steve * Update DFF support to new data flow. * diff --git a/vvp/README.txt b/vvp/README.txt index f009d7215..0aa9c93e4 100644 --- a/vvp/README.txt +++ b/vvp/README.txt @@ -1,7 +1,7 @@ /* * Copyright (c) 2001 Stephen Williams (steve@icarus.com) * - * $Id: README.txt,v 1.65 2005/05/01 22:05:21 steve Exp $ + * $Id: README.txt,v 1.66 2005/05/08 23:40:14 steve Exp $ */ VVP SIMULATION ENGINE @@ -459,6 +459,7 @@ bit number, and a width. Normally, those bits are constant values.