From b8bc531f0519d774af12f4828d8353c74065ce99 Mon Sep 17 00:00:00 2001 From: steve Date: Sun, 12 Mar 2006 07:34:16 +0000 Subject: [PATCH] Fix the memsynth1 case. --- design_dump.cc | 13 +++++++-- ivl_target.h | 33 +++++++++++++++++---- net_assign.cc | 18 ++++++++++-- net_nex_output.cc | 45 +++++++++++++++++++++++------ netlist.cc | 34 ++++++++++++++++++++-- netlist.h | 24 ++++++++++++++-- synth2.cc | 62 +++++++++++++++++++++++++++++++++++---- t-dll-api.cc | 26 +++++++++++++++-- t-dll-expr.cc | 63 +++++++++++++++++++++++++++++++++++----- t-dll.cc | 32 ++++++++++++++++++--- t-dll.h | 6 +++- tgt-stub/stub.c | 47 ++++++++++++++++++++++++++++-- tgt-vvp/eval_expr.c | 43 +++++++++++++++++++++++++++- tgt-vvp/vvp_scope.c | 70 ++++++++++++++++++++++++++++++++++++++------- vvp/compile.h | 8 ++++-- vvp/decoder.cc | 40 +++++++++++++++++++------- vvp/parse.y | 9 ++++-- 17 files changed, 501 insertions(+), 72 deletions(-) diff --git a/design_dump.cc b/design_dump.cc index 1a7d5a41d..c616e01a6 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: design_dump.cc,v 1.149.2.2 2006/02/19 00:11:31 steve Exp $" +#ident "$Id: design_dump.cc,v 1.149.2.3 2006/03/12 07:34:16 steve Exp $" #endif # include "config.h" @@ -219,7 +219,7 @@ void NetCompare::dump_node(ostream&o, unsigned ind) const void NetDecode::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << "LPM_DECODE (NetDecode): " << name() - << " ff=" << ff_->name() << endl; + << " ff=" << ff_->name() << ", word width=" << width() << endl; dump_node_pins(o, ind+4); dump_obj_attr(o, ind+4); } @@ -369,7 +369,11 @@ void NetRamDq::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << "LPM_RAM_DQ ("; - if (mem_) o << "mem=" << mem_->name(); + if (mem_) + if (NetNet*tmp = mem_->reg_from_explode()) + o << "exploded mem=" << tmp->name(); + else + o << "mem=" << mem_->name(); o << "): " << name() << endl; @@ -1105,6 +1109,9 @@ void Design::dump(ostream&o) const /* * $Log: design_dump.cc,v $ + * Revision 1.149.2.3 2006/03/12 07:34:16 steve + * Fix the memsynth1 case. + * * Revision 1.149.2.2 2006/02/19 00:11:31 steve * Handle synthesis of FF vectors with l-value decoder. * diff --git a/ivl_target.h b/ivl_target.h index b7eefdf46..975bf13ee 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.126.2.2 2006/02/25 05:03:28 steve Exp $" +#ident "$Id: ivl_target.h,v 1.126.2.3 2006/03/12 07:34:16 steve Exp $" #endif #ifdef __cplusplus @@ -675,9 +675,16 @@ extern const char* ivl_udp_name(ivl_udp_t net); * - IVL_LPM_FF * The IVL_LPM_FF and IVL_LPM_DECODE devices are closely related. If * the ivl_lpm_decode function returns a non-nil value, then the - * decoder represents an extra ENABLE-like input, where exactly one(1) - * bit of the width of the FF is enabled. The decoder inputs are and - * address that selects the FF to be enabled. + * decoder represents an extra ENABLE-like input, where exactly + * bits of the width of the FF is enabled. The ivl_lpm_width of the + * decoder defines . + * + * The decoder inputs are the address that selects the FF to be + * enabled, and the ivl_lpm_selects for the decoder gives the width of + * the address. The address of the LSB of the memory, then, is the + * word width times the input address. For a simple l-value bit + * select, the word width will be 1, and the address goes directly + * to the bit. Otherwise, *address gets to the first bit of the word. * * The core compiler generates these attributes in certain cases: * @@ -685,6 +692,19 @@ extern const char* ivl_udp_name(ivl_udp_t net); * If present, the string value can be "INVERT". That indicates * that the clock is negedge sensitive instead of the default * posedge sensitive. + * + * - IVL_LPM_RAM + * The IVL_LPM_RAM may also appear as a READ port for a FF array. In + * this case, the IVL_LPM_RAM device has an ivl_lpm_width that is the + * width of the word, and an ivl_lpm_size that is the number of words + * in the array. In effect, the IVL_LPM_RAM reorganizes a vector into + * an array of words. If this is happening, then the ivl_lpm_memory + * will return 0. + * + * The ivl_lpm_q function gets the output nexa of the read port. The + * "q" port has as many bits as the width. The ivl_lpm_data2 function + * gets the nexa of the input, with the sdx the word address and the + * idx the bit within the word. */ extern const char* ivl_lpm_name(ivl_lpm_t net); /* (Obsolete) */ @@ -727,7 +747,7 @@ extern ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx); extern unsigned ivl_lpm_selects(ivl_lpm_t net); /* IVL_LPM_MUX IVL_LPM_DECODE IVL_LPM_RAM */ extern ivl_nexus_t ivl_lpm_select(ivl_lpm_t net, unsigned idx); - /* IVL_LPM_MUX */ + /* IVL_LPM_MUX, IVL_LPM_RAM */ extern unsigned ivl_lpm_size(ivl_lpm_t net); /* IVL_LPM_RAM */ extern ivl_memory_t ivl_lpm_memory(ivl_lpm_t net); @@ -1268,6 +1288,9 @@ _END_DECL /* * $Log: ivl_target.h,v $ + * Revision 1.126.2.3 2006/03/12 07:34:16 steve + * Fix the memsynth1 case. + * * Revision 1.126.2.2 2006/02/25 05:03:28 steve * Add support for negedge FFs by using attributes. * diff --git a/net_assign.cc b/net_assign.cc index 3609dcf9d..9ab26e6a9 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: net_assign.cc,v 1.18 2004/08/28 15:08:31 steve Exp $" +#ident "$Id: net_assign.cc,v 1.18.2.1 2006/03/12 07:34:17 steve Exp $" #endif # include "config.h" @@ -71,6 +71,14 @@ NetAssign_::~NetAssign_() sig_->type(NetNet::WIRE); } + if (mem_) { + NetNet*exp = mem_->reg_from_explode(); + if (exp) { + exp->decr_lref(); + if (turn_sig_to_wire_on_release_ && exp->peek_lref() == 0) + exp->type(NetNet::WIRE); + } + } assert( more == 0 ); if (bmux_) delete bmux_; } @@ -111,7 +119,10 @@ perm_string NetAssign_::name() const NetNet* NetAssign_::sig() const { - return sig_; + if (mem_) + return 0; + else + return sig_; } NetMemory* NetAssign_::mem() const @@ -261,6 +272,9 @@ NetAssignNB::~NetAssignNB() /* * $Log: net_assign.cc,v $ + * Revision 1.18.2.1 2006/03/12 07:34:17 steve + * Fix the memsynth1 case. + * * Revision 1.18 2004/08/28 15:08:31 steve * Do not change reg to wire in NetAssign_ unless synthesizing. * diff --git a/net_nex_output.cc b/net_nex_output.cc index 63c5ba2fe..4cab98c09 100644 --- a/net_nex_output.cc +++ b/net_nex_output.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: net_nex_output.cc,v 1.11.2.1 2006/01/18 01:23:23 steve Exp $" +#ident "$Id: net_nex_output.cc,v 1.11.2.2 2006/03/12 07:34:17 steve Exp $" #endif # include "config.h" @@ -47,18 +47,42 @@ void NetAssignBase::nex_output(NexusSet&out) { for (NetAssign_*cur = lval_ ; cur ; cur = cur->more) { if (NetNet*lsig = cur->sig()) { -#if 0 - if (cur->bmux()) { - cerr << get_line() << ": internal error: " - << "L-Value mux not supported by nex_output: "; - cur->dump_lval(cerr); - cerr << endl; - } -#endif + + /* Handle l-value signals. We don't need to worry + here about whether there is a bmux, because the + synthesizer will detect that mux and create a + decoder between the expression and the signal. */ for (unsigned idx = 0 ; idx < cur->lwidth() ; idx += 1) { unsigned off = cur->get_loff() + idx; out.add(lsig->pin(off).nexus()); } + + } else if (NetMemory*lmem = cur->mem()) { + + /* Memories here are treated as a bunch of reg + devices. Use the explode_to_reg method to get + access to the FF version of the memory and use + that in our l-value management. */ + NetNet*tmp = lmem->explode_to_reg(); + + if (NetEConst*ae = dynamic_cast(cur->bmux())) { + /* The address is constant, so simply + connect to the right pins and we are + done. */ + long adr= ae->value().as_long(); + adr = lmem->index_to_address(adr) * lmem->width(); + + for (unsigned idx = 0; idx < cur->lwidth(); idx += 1) + out.add(tmp->pin(adr+idx).nexus()); + + } else { + /* Fake an address of 0. The context will + actually shove a decoder in place here. */ + long adr= 0; + for (unsigned idx = 0; idx < cur->lwidth(); idx += 1) + out.add(tmp->pin(adr+idx).nexus()); + } + } else { /* Quoting from netlist.h comments for class NetMemory: * "This is not a node because memory objects can only be @@ -130,6 +154,9 @@ void NetWhile::nex_output(NexusSet&out) /* * $Log: net_nex_output.cc,v $ + * Revision 1.11.2.2 2006/03/12 07:34:17 steve + * Fix the memsynth1 case. + * * Revision 1.11.2.1 2006/01/18 01:23:23 steve * Rework l-value handling to allow for more l-value type flexibility. * diff --git a/netlist.cc b/netlist.cc index eab27ed95..0a45e75ae 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.226.2.2 2006/02/19 00:11:32 steve Exp $" +#ident "$Id: netlist.cc,v 1.226.2.3 2006/03/12 07:34:17 steve Exp $" #endif # include "config.h" @@ -686,6 +686,11 @@ const verinum& NetFF::sset_value() const return sset_value_; } +unsigned NetDecode::width() const +{ + return width_; +} + unsigned NetDecode::awidth() const { return pin_count(); @@ -1076,9 +1081,13 @@ const Link& NetCompare::pin_DataB(unsigned idx) const return pin(8+width_+idx); } -NetDecode::NetDecode(NetScope*s, perm_string name, NetFF*mem, unsigned awid) +NetDecode::NetDecode(NetScope*s, perm_string name, NetFF*mem, + unsigned awid, unsigned word_width) : NetNode(s, name, awid) { + width_ = word_width; + assert( mem->width() % width_ == 0 ); + ff_ = mem; ff_->demux_ = this; make_pins_(awid); @@ -2057,6 +2066,7 @@ NetMemory::NetMemory(NetScope*sc, perm_string n, long w, long s, long e) : width_(w), idxh_(s), idxl_(e), ram_list_(0), scope_(sc) { name_ = n; + explode_ = 0; scope_->add_memory(this); } @@ -2087,7 +2097,24 @@ unsigned NetMemory::index_to_address(long idx) const return idx - idxl_; } +NetNet* NetMemory::explode_to_reg() +{ + if (explode_) + return explode_; + explode_ = new NetNet(scope_, name_, NetNet::REG, count()*width_); + return explode_; +} + +NetNet* NetMemory::reg_from_explode() +{ + return explode_; +} + +const NetNet* NetMemory::reg_from_explode() const +{ + return explode_; +} NetEMemory* NetEMemory::dup_expr() const { @@ -2335,6 +2362,9 @@ const NetProc*NetTaskDef::proc() const /* * $Log: netlist.cc,v $ + * Revision 1.226.2.3 2006/03/12 07:34:17 steve + * Fix the memsynth1 case. + * * Revision 1.226.2.2 2006/02/19 00:11:32 steve * Handle synthesis of FF vectors with l-value decoder. * diff --git a/netlist.h b/netlist.h index c9dfb318d..96d552e9e 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.321.2.10 2006/02/19 00:11:32 steve Exp $" +#ident "$Id: netlist.h,v 1.321.2.11 2006/03/12 07:34:17 steve Exp $" #endif /* @@ -599,9 +599,15 @@ class NetCompare : public NetNode { class NetDecode : public NetNode { public: - NetDecode(NetScope*s, perm_string name, NetFF*mem, unsigned awid); + NetDecode(NetScope*s, perm_string name, NetFF*mem, + unsigned awid, unsigned word_width); ~NetDecode(); + // This is the width of the word. The width of the NetFF mem + // is an even multiple of this. + unsigned width() const; + // This is the width of the address. The address value for the + // base of a word is the address * width(). unsigned awidth() const; const NetFF*ff() const; @@ -615,6 +621,7 @@ class NetDecode : public NetNode { virtual bool emit_node(struct target_t*) const; private: + unsigned width_; NetFF* ff_; private: @@ -784,6 +791,7 @@ class NetMemory { // NetScope*scope(); const NetScope*scope() const { return scope_; }; + NetScope*scope() { return scope_; }; // This is the number of memory positions. unsigned count() const; @@ -793,6 +801,13 @@ class NetMemory { // that are not zero based. unsigned index_to_address(long idx) const; + // This method returns a NetNet::REG that has the same number + // of bits as the memory as a whole. This is used to represent + // memories that are synthesized to individual bits. + NetNet* explode_to_reg(); + NetNet* reg_from_explode(); + const NetNet* reg_from_explode() const; + void dump(ostream&o, unsigned lm) const; private: @@ -808,6 +823,8 @@ class NetMemory { NetMemory*snext_, *sprev_; NetScope*scope_; + NetNet*explode_; + private: // not implemented NetMemory(const NetMemory&); NetMemory& operator= (const NetMemory&); @@ -3439,6 +3456,9 @@ extern ostream& operator << (ostream&, NetNet::Type); /* * $Log: netlist.h,v $ + * Revision 1.321.2.11 2006/03/12 07:34:17 steve + * Fix the memsynth1 case. + * * Revision 1.321.2.10 2006/02/19 00:11:32 steve * Handle synthesis of FF vectors with l-value decoder. * diff --git a/synth2.cc b/synth2.cc index 299e7e57a..e28970dbf 100644 --- a/synth2.cc +++ b/synth2.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: synth2.cc,v 1.39.2.22 2006/02/25 05:03:29 steve Exp $" +#ident "$Id: synth2.cc,v 1.39.2.23 2006/03/12 07:34:18 steve Exp $" #endif # include "config.h" @@ -105,6 +105,44 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope, bool sync_flag, for (NetAssign_*cur = lval_ ; cur ; cur = cur->more) { + NetMemory*lmem = cur->mem(); + if (lmem && !sync_flag) { + cerr << get_line() << ": error: Cannot synthesize memory " + << "assignment is asynchronous logic." << endl; + des->errors += 1; + return false; + } + + /* Is this an assignment to a memory? If so, then + explode the memory to an array of reg bits. The + context that is calling this will attach a decoder + between the ff and the r-val. In fact, the memory at + this point has already been scanned and exploded, so + the explode_to_reg method below will return a + pre-existing vector. + + Note that this is only workable if we are in the + asynchronous path of a synchronous thread. The + sync_flag must be true in this case. */ + if (lmem) { + assert(sync_flag); + NetNet*msig = lmem->explode_to_reg(); + msig->incr_lref(); + + if (NetEConst*ae = dynamic_cast(cur->bmux())) { + long adr= ae->value().as_long(); + adr = lmem->index_to_address(adr) * lmem->width(); + for (unsigned idx = 0 ; idx < cur->lwidth() ; idx += 1) { + unsigned off = adr+idx; + unsigned ptr = find_nexus_in_set(nex_map, msig->pin(off).nexus()); + assert(ptr <= nex_map->pin_count()); + connect(nex_out->pin(ptr), rsig->pin(roff+idx)); + } + } + continue; + } + + NetNet*lsig = cur->sig(); if (!lsig) { cerr << get_line() << ": error: NetAssignBase::synth_async " @@ -851,6 +889,8 @@ bool NetAssignBase::synth_sync(Design*des, NetScope*scope, for (NetAssign_*cur = lval_ ; cur ; cur = cur->more) { if (cur->bmux()) demux = cur; + if (cur->mem()) + demux = cur; count_lval += 1; } @@ -872,7 +912,8 @@ bool NetAssignBase::synth_sync(Design*des, NetScope*scope, NetNet*adr = demux->bmux()->synthesize(des); NetDecode*dq = new NetDecode(scope, scope->local_symbol(), - nex_ff[0].ff, adr->pin_count()); + nex_ff[0].ff, adr->pin_count(), + lval_->lwidth()); des->add_node(dq); dq->set_line(*this); @@ -880,11 +921,16 @@ bool NetAssignBase::synth_sync(Design*des, NetScope*scope, connect(dq->pin_Address(idx), adr->pin(idx)); NetNet*rsig = rval_->synthesize(des); - assert(rsig->pin_count() == 1); + assert(rsig->pin_count() == lval_->lwidth()); for (unsigned idx = 0 ; idx < nex_ff[0].ff->width() ; idx += 1) - connect(nex_ff[0].ff->pin_Data(idx), rsig->pin(0)); + connect(nex_ff[0].ff->pin_Data(idx), rsig->pin(idx%lval_->lwidth())); + if (lval_->mem()) { + NetNet*exp = lval_->mem()->reg_from_explode(); + assert(exp); + exp->incr_lref(); + } lval_->turn_sig_to_wire_on_release(); return true; } @@ -1269,7 +1315,10 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope, Also, we will not allow both Sset and Sclr to be used on a single LPM_FF (due to unclear priority issues) so don't try - if either are already connected. */ + if either are already connected. + + XXXX This should be disabled if there is a memory involved + in any sub-statements? */ assert(if_ != 0); NexusSet*a_set = if_->nex_input(); @@ -1639,6 +1688,9 @@ void synth2(Design*des) /* * $Log: synth2.cc,v $ + * Revision 1.39.2.23 2006/03/12 07:34:18 steve + * Fix the memsynth1 case. + * * Revision 1.39.2.22 2006/02/25 05:03:29 steve * Add support for negedge FFs by using attributes. * diff --git a/t-dll-api.cc b/t-dll-api.cc index bcc48784b..9a8778388 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.108.2.2 2006/02/25 05:03:29 steve Exp $" +#ident "$Id: t-dll-api.cc,v 1.108.2.3 2006/03/12 07:34:19 steve Exp $" #endif # include "config.h" @@ -826,6 +826,22 @@ extern "C" ivl_nexus_t ivl_lpm_data2(ivl_lpm_t net, unsigned sdx, unsigned idx) return net->u_.ufunc.pins[base+idx]; } + case IVL_LPM_RAM: + if (net->u_.ff.a.mem == 0) { + // This is an exploded RAM, so we use sdx and idx + // to address a nexa into the exploded ram. + if (sdx >= net->u_.ff.scnt) + return 0; + if (idx >= net->u_.ff.width) + return 0; + unsigned adr = sdx * net->u_.ff.width + idx; + return net->u_.ff.d.pins[adr]; + + } else { + // Normal RAM port does not have data2 nexa + return 0; + } + default: assert(0); return 0; @@ -1025,6 +1041,8 @@ extern "C" unsigned ivl_lpm_size(ivl_lpm_t net) switch (net->type) { case IVL_LPM_MUX: return net->u_.mux.size; + case IVL_LPM_RAM: + return net->u_.ff.scnt; case IVL_LPM_UFUNC: return net->u_.ufunc.ports - 1; default: @@ -1045,6 +1063,7 @@ extern "C" unsigned ivl_lpm_width(ivl_lpm_t net) case IVL_LPM_FF: case IVL_LPM_RAM: return net->u_.ff.width; + case IVL_LPM_DECODE: case IVL_LPM_MUX: return net->u_.mux.width; case IVL_LPM_ADD: @@ -1062,8 +1081,6 @@ extern "C" unsigned ivl_lpm_width(ivl_lpm_t net) return net->u_.shift.width; case IVL_LPM_UFUNC: return net->u_.ufunc.port_wid[0]; - case IVL_LPM_DECODE: - return 1; default: assert(0); return 0; @@ -1964,6 +1981,9 @@ extern "C" ivl_variable_type_t ivl_variable_type(ivl_variable_t net) /* * $Log: t-dll-api.cc,v $ + * Revision 1.108.2.3 2006/03/12 07:34:19 steve + * Fix the memsynth1 case. + * * Revision 1.108.2.2 2006/02/25 05:03:29 steve * Add support for negedge FFs by using attributes. * diff --git a/t-dll-expr.cc b/t-dll-expr.cc index e2e6353e0..4fc4ec1bb 100644 --- a/t-dll-expr.cc +++ b/t-dll-expr.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-expr.cc,v 1.39 2004/06/17 16:06:19 steve Exp $" +#ident "$Id: t-dll-expr.cc,v 1.39.2.1 2006/03/12 07:34:19 steve Exp $" #endif # include "config.h" @@ -222,12 +222,58 @@ void dll_target::expr_memory(const NetEMemory*net) ivl_expr_t cur = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); assert(cur); - cur->type_ = IVL_EX_MEMORY; - cur->value_ = IVL_VT_VECTOR; - cur->width_= net->expr_width(); - cur->signed_ = net->has_sign()? 1 : 0; - cur->u_.memory_.mem_ = find_memory(des_, net->memory()); - cur->u_.memory_.idx_ = expr_; + const NetMemory*mem = net->memory(); + + if (const NetNet*reg = mem->reg_from_explode()) { + + cur->type_ = IVL_EX_SELECT; + cur->value_ = IVL_VT_VECTOR; + cur->width_ = net->expr_width(); + cur->signed_ = net->has_sign()? 1 : 0; + + // Create an expression form of the exploded + // memory. This is what the select will apply to. + ivl_expr_t sig = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); + sig->type_ = IVL_EX_SIGNAL; + sig->value_ = IVL_VT_VECTOR; + sig->width_ = reg->pin_count(); + sig->signed_ = 0; + sig->u_.signal_.sig = find_signal(des_, reg); + sig->u_.signal_.lsi = 0; + sig->u_.signal_.msi = reg->pin_count()-1; + cur->u_.binary_.lef_ = sig; + + // Create an expression of the address calculation. + cur->u_.binary_.rig_ = expr_; + + if (cur->width_ > 1) { + ivl_expr_t mul = (ivl_expr_t)calloc(2, sizeof(struct ivl_expr_s)); + ivl_expr_t fac = mul+1; + + fac->type_ = IVL_EX_ULONG; + fac->value_ = IVL_VT_VECTOR; + fac->width_ = 8*sizeof(cur->width_); + fac->signed_= 0; + fac->u_.ulong_.value = cur->width_; + + mul->type_ = IVL_EX_BINARY; + mul->value_ = IVL_VT_VECTOR; + mul->width_ = fac->width_; + mul->signed_= 0; + mul->u_.binary_.op_ = '*'; + mul->u_.binary_.lef_ = cur->u_.binary_.rig_; + mul->u_.binary_.rig_ = fac; + cur->u_.binary_.rig_ = mul; + } + + } else { + cur->type_ = IVL_EX_MEMORY; + cur->value_ = IVL_VT_VECTOR; + cur->width_= net->expr_width(); + cur->signed_ = net->has_sign()? 1 : 0; + cur->u_.memory_.mem_ = find_memory(des_, net->memory()); + cur->u_.memory_.idx_ = expr_; + } expr_ = cur; } @@ -604,6 +650,9 @@ void dll_target::expr_variable(const NetEVariable*net) /* * $Log: t-dll-expr.cc,v $ + * Revision 1.39.2.1 2006/03/12 07:34:19 steve + * Fix the memsynth1 case. + * * Revision 1.39 2004/06/17 16:06:19 steve * Help system function signedness survive elaboration. * diff --git a/t-dll.cc b/t-dll.cc index 7f0c5578a..7b9ac023e 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.131.2.4 2006/02/25 05:03:29 steve Exp $" +#ident "$Id: t-dll.cc,v 1.131.2.5 2006/03/12 07:34:19 steve Exp $" #endif # include "config.h" @@ -1522,7 +1522,7 @@ ivl_lpm_t dll_target::lpm_decode_ff_(const NetDecode*net) obj->u_.mux.swid = net->awidth(); obj->u_.mux.size = 0; - obj->u_.mux.width = 0; + obj->u_.mux.width = net->width(); obj->u_.mux.d = 0; if (obj->u_.mux.swid > 1) { @@ -1671,18 +1671,23 @@ void dll_target::lpm_ff(const NetFF*net) void dll_target::lpm_ram_dq(const NetRamDq*net) { + ivl_memory_t mem = find_memory(des_, net->mem()); + assert(mem); + + const NetNet*ereg = net->mem()->reg_from_explode(); + ivl_lpm_t obj = new struct ivl_lpm_s; obj->type = IVL_LPM_RAM; obj->name = net->name(); obj->attr = 0; obj->nattr = 0; - obj->u_.ff.a.mem = find_memory(des_, net->mem()); - assert(obj->u_.ff.a.mem); + obj->u_.ff.a.mem = ereg? 0 : mem; obj->scope = find_scope(des_, net->mem()->scope()); assert(obj->scope); obj->u_.ff.width = net->width(); obj->u_.ff.swid = net->awidth(); + obj->u_.ff.scnt = net->mem()->count(); scope_add_lpm(obj->scope, obj); @@ -1692,6 +1697,7 @@ void dll_target::lpm_ram_dq(const NetRamDq*net) // the clock input. bool has_write_port = net->pin_InClock().is_linked(); + assert( ereg? !has_write_port : 1 ); // Connect the write clock and write enable @@ -1783,6 +1789,21 @@ void dll_target::lpm_ram_dq(const NetRamDq*net) IVL_DR_STRONG, IVL_DR_STRONG); } } + + if (ereg) { + unsigned count = obj->u_.ff.width * obj->u_.ff.scnt; + assert(ereg->pin_count() == count); + + obj->u_.ff.d.pins = new ivl_nexus_t [count]; + + for (unsigned idx = 0 ; idx < count ; idx += 1) { + nex = ereg->pin(idx).nexus(); + assert(nex->t_cookie()); + obj->u_.ff.d.pins[idx] = (ivl_nexus_t) nex->t_cookie(); + nexus_lpm_add(obj->u_.ff.d.pins[idx], obj, 0, + IVL_DR_HiZ, IVL_DR_HiZ); + } + } } void dll_target::lpm_mult(const NetMult*net) @@ -2250,6 +2271,9 @@ extern const struct target tgt_dll = { "dll", &dll_target_obj }; /* * $Log: t-dll.cc,v $ + * Revision 1.131.2.5 2006/03/12 07:34:19 steve + * Fix the memsynth1 case. + * * Revision 1.131.2.4 2006/02/25 05:03:29 steve * Add support for negedge FFs by using attributes. * diff --git a/t-dll.h b/t-dll.h index db2067a6d..e70d0468b 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.115.2.2 2006/02/25 05:03:30 steve Exp $" +#ident "$Id: t-dll.h,v 1.115.2.3 2006/03/12 07:34:19 steve Exp $" #endif # include "target.h" @@ -300,6 +300,7 @@ struct ivl_lpm_s { struct ivl_lpm_ff_s { unsigned width; unsigned swid; // ram only + unsigned scnt; ivl_nexus_t clk; ivl_nexus_t we; ivl_nexus_t aclr; @@ -693,6 +694,9 @@ struct ivl_variable_s { /* * $Log: t-dll.h,v $ + * Revision 1.115.2.3 2006/03/12 07:34:19 steve + * Fix the memsynth1 case. + * * Revision 1.115.2.2 2006/02/25 05:03:30 steve * Add support for negedge FFs by using attributes. * diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index c686216ce..71db83dc1 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.90.2.6 2006/02/25 05:03:30 steve Exp $" +#ident "$Id: stub.c,v 1.90.2.7 2006/03/12 07:34:20 steve Exp $" #endif # include "config.h" @@ -112,6 +112,12 @@ static void show_expression(ivl_expr_t net, unsigned ind) break; } + case IVL_EX_ULONG: { + fprintf(out, "%*s\n", + ind, "", width, ivl_expr_uvalue(net), sign); + break; + } + case IVL_EX_SELECT: /* The SELECT expression can be used to express part select, or if the base is null vector extension. */ @@ -198,6 +204,35 @@ static void show_expression(ivl_expr_t net, unsigned ind) } } +static void show_lpm_ram(ivl_lpm_t net) +{ + unsigned width = ivl_lpm_width(net); + unsigned count = ivl_lpm_size(net); + + unsigned idx, sdx; + + fprintf(out, " LPM_RAM_DQ %s (word-width=%u, count=%u)\n", + ivl_lpm_basename(net), ivl_lpm_width(net), count); + for (idx = 0 ; idx < ivl_lpm_selects(net) ; idx += 1) { + ivl_nexus_t nex = ivl_lpm_select(net, idx); + fprintf(out, " Address %u: %s\n", idx, + nex? ivl_nexus_name(nex) : ""); + } + + for (idx = 0 ; idx < width ; idx += 1) { + ivl_nexus_t nex = ivl_lpm_q(net, idx); + fprintf(out, " Q %u: %s\n", idx, nex? ivl_nexus_name(nex) : ""); + } + + for (sdx = 0 ; sdx < count ; sdx += 1) { + for (idx = 0 ; idx < width ; idx += 1) { + ivl_nexus_t nex = ivl_lpm_data2(net, sdx, idx); + fprintf(out, " Word%u %u: %s\n", + sdx, idx, nex? ivl_nexus_name(nex) : ""); + } + } +} + static void show_lpm(ivl_lpm_t net) { unsigned idx; @@ -296,7 +331,8 @@ static void show_lpm(ivl_lpm_t net) } case IVL_LPM_DECODE: { - fprintf(out, " LPM_DECODE %s\n", ivl_lpm_basename(net)); + fprintf(out, " LPM_DECODE %s (word-width=%u)\n", + ivl_lpm_basename(net), ivl_lpm_width(net)); for (idx = 0 ; idx < ivl_lpm_selects(net) ; idx += 1) { ivl_nexus_t nex = ivl_lpm_select(net, idx); fprintf(out, " Address %u: %s\n", idx, @@ -305,6 +341,10 @@ static void show_lpm(ivl_lpm_t net) break; } + case IVL_LPM_RAM: + show_lpm_ram(net); + break; + case IVL_LPM_SHIFTL: { fprintf(out, " LPM_SHIFTL %s: \n", ivl_lpm_basename(net), width, ivl_lpm_selects(net), @@ -1033,6 +1073,9 @@ int target_design(ivl_design_t des) /* * $Log: stub.c,v $ + * Revision 1.90.2.7 2006/03/12 07:34:20 steve + * Fix the memsynth1 case. + * * Revision 1.90.2.6 2006/02/25 05:03:30 steve * Add support for negedge FFs by using attributes. * diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index f5d3fb2b2..122e27a5f 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: eval_expr.c,v 1.110 2004/10/04 01:10:57 steve Exp $" +#ident "$Id: eval_expr.c,v 1.110.2.1 2006/03/12 07:34:20 steve Exp $" #endif # include "vvp_priv.h" @@ -1841,6 +1841,40 @@ static struct vector_info draw_ufunc_expr(ivl_expr_t exp, unsigned wid) return res; } +static struct vector_info draw_ulong_expr(ivl_expr_t exp, unsigned wid) +{ + unsigned long idx; + struct vector_info res; + unsigned long uval = ivl_expr_uvalue(exp); + + if (uval == 0) { + res.wid = wid; + res.base = 0; + return res; + } + + res.base = allocate_vector(wid); + res.wid = wid; + + idx = 0; + while (idx < wid) { + unsigned long cnt; + + int bit = 1 & (uval >> idx); + for (cnt = 1 ; idx+cnt < wid ; cnt += 1) { + int tmp = 1 & (uval >> (idx+cnt)); + if (tmp != bit) + break; + } + + fprintf(vvp_out, " %%mov %u, %d, %lu;\n", + res.base+idx, bit, cnt); + idx += cnt; + } + + return res; +} + static struct vector_info draw_unary_expr(ivl_expr_t exp, unsigned wid) { struct vector_info res; @@ -2120,6 +2154,10 @@ struct vector_info draw_eval_expr_wid(ivl_expr_t exp, unsigned wid, res = draw_ufunc_expr(exp, wid); break; + case IVL_EX_ULONG: + res = draw_ulong_expr(exp, wid); + break; + case IVL_EX_UNARY: res = draw_unary_expr(exp, wid); break; @@ -2139,6 +2177,9 @@ struct vector_info draw_eval_expr(ivl_expr_t exp, int stuff_ok_flag) /* * $Log: eval_expr.c,v $ + * Revision 1.110.2.1 2006/03/12 07:34:20 steve + * Fix the memsynth1 case. + * * Revision 1.110 2004/10/04 01:10:57 steve * Clean up spurious trailing white space. * diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 7c496d878..7c7484f7c 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.103.2.3 2006/02/25 05:03:30 steve Exp $" +#ident "$Id: vvp_scope.c,v 1.103.2.4 2006/03/12 07:34:20 steve Exp $" #endif # include "vvp_priv.h" @@ -411,7 +411,29 @@ static const char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) } break; + /* The output for a RAM depends on whether it is + exploded or not. If it is, treat is like a MUX. If it + is not, treat it like an arithmetic LPM. */ case IVL_LPM_RAM: + if (ivl_lpm_memory(lpm)) { + for (idx = 0 ; idx < ivl_lpm_width(lpm) ; idx += 1) { + if (ivl_lpm_q(lpm, idx) == nex) { + sprintf(result, "L_%p[%u]", lpm, idx); + return result; + } + } + } else { + for (idx = 0 ; idx < ivl_lpm_width(lpm) ; idx += 1) { + if (ivl_lpm_q(lpm, idx) == nex) { + sprintf(result, "L_%s.%s/%u", + vvp_mangle_id(ivl_scope_name(ivl_lpm_scope(lpm))), + vvp_mangle_id(ivl_lpm_basename(lpm)), idx); + return result; + } + } + } + break; + case IVL_LPM_ADD: case IVL_LPM_SHIFTL: case IVL_LPM_SHIFTR: @@ -1105,7 +1127,13 @@ static void draw_event_in_scope(ivl_event_t obj) } } -inline static void draw_lpm_ram(ivl_lpm_t net) +static void draw_lpm_ram_exploded(ivl_lpm_t net) +{ + fprintf(vvp_out, "; exploded ram port!\n"); + draw_lpm_mux(net); +} + +static void draw_lpm_ram(ivl_lpm_t net) { unsigned idx; unsigned width = ivl_lpm_width(net); @@ -1114,6 +1142,11 @@ inline static void draw_lpm_ram(ivl_lpm_t net) ivl_nexus_t clk = ivl_lpm_clk(net); ivl_nexus_t pin; + if (mem == 0) { + draw_lpm_ram_exploded(net); + return; + } + if (clk) { fprintf(vvp_out, "CLK_%p .event posedge, ", net); draw_input_from_net(clk); @@ -1317,6 +1350,7 @@ static void draw_lpm_ff(ivl_lpm_t net) unsigned width, idx; ivl_attribute_t clock_pol = find_lpm_attr(net, "ivl:clock_polarity"); + ivl_lpm_t decode = ivl_lpm_decode(net); width = ivl_lpm_width(net); @@ -1408,23 +1442,34 @@ static void draw_lpm_ff(ivl_lpm_t net) } /* If there is a decoder for this FF, then create a - decoder enable node. */ - if (ivl_lpm_decode(net)) { + decoder enable node. The .decode/en arguments are the + label for the .decode/adr, a .decoder/en slice + number (the address it responds to), the label for a + decoder enable, and the label for a mass-write enable. */ + if (decode) { ivl_lpm_t dec = ivl_lpm_decode(net); fprintf(vvp_out, "L_%s.%s/dec/%u .decode/en L_%s.%s, %u", vvp_mangle_id(ivl_scope_name(ivl_lpm_scope(net))), - vvp_mangle_id(ivl_lpm_basename(net)), idx, + vvp_mangle_id(ivl_lpm_basename(net)), + idx, vvp_mangle_id(ivl_scope_name(ivl_lpm_scope(dec))), - vvp_mangle_id(ivl_lpm_basename(dec)), idx); + vvp_mangle_id(ivl_lpm_basename(dec)), + idx / ivl_lpm_width(decode)); tmp = ivl_lpm_enable(net); - if (tmp && (ivl_lpm_sync_clr(net)||ivl_lpm_sync_set(net))) { - fprintf(vvp_out, ", L_%s.%s/en", - vvp_mangle_id(ivl_scope_name(ivl_lpm_scope(net))), - vvp_mangle_id(ivl_lpm_basename(net))); - } else if (tmp) { + if (tmp) { fprintf(vvp_out, ", "); draw_input_from_net(tmp); + } else { + fprintf(vvp_out, ", C<1> "); + } + fprintf(vvp_out, ", "); + if (ivl_lpm_sync_clr(net)) { + draw_input_from_net(ivl_lpm_sync_clr(net)); + } else if (ivl_lpm_sync_set(net)) { + draw_input_from_net(ivl_lpm_sync_set(net)); + } else { + fprintf(vvp_out, "C<0>"); } fprintf(vvp_out, ";\n"); } @@ -1776,6 +1821,9 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) /* * $Log: vvp_scope.c,v $ + * Revision 1.103.2.4 2006/03/12 07:34:20 steve + * Fix the memsynth1 case. + * * Revision 1.103.2.3 2006/02/25 05:03:30 steve * Add support for negedge FFs by using attributes. * diff --git a/vvp/compile.h b/vvp/compile.h index 9df29d1d1..44f1a1c6b 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: compile.h,v 1.56.2.1 2006/02/19 00:11:35 steve Exp $" +#ident "$Id: compile.h,v 1.56.2.2 2006/03/12 07:34:21 steve Exp $" #endif # include @@ -118,7 +118,8 @@ extern void compile_cmp_gt(char*label, long width, bool signed_flag, extern void compile_decode_adr(char*label, unsigned argc, struct symb_s*argv); extern void compile_decode_en(char*label, char*decoder, int slice, - struct symb_s enable); + struct symb_s enable, + struct symb_s mass_enable); extern void compile_shiftl(char*label, long width, unsigned argc, struct symb_s*argv); extern void compile_shiftr(char*label, long width, @@ -272,6 +273,9 @@ extern void compile_net(char*label, char*name, /* * $Log: compile.h,v $ + * Revision 1.56.2.2 2006/03/12 07:34:21 steve + * Fix the memsynth1 case. + * * Revision 1.56.2.1 2006/02/19 00:11:35 steve * Handle synthesis of FF vectors with l-value decoder. * diff --git a/vvp/decoder.cc b/vvp/decoder.cc index 917ab8bf4..5e031fe0c 100644 --- a/vvp/decoder.cc +++ b/vvp/decoder.cc @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ident "$Id: decoder.cc,v 1.1.2.1 2006/02/19 00:11:36 steve Exp $" +#ident "$Id: decoder.cc,v 1.1.2.2 2006/03/12 07:34:21 steve Exp $" # include "compile.h" # include "functor.h" @@ -86,6 +86,8 @@ struct vvp_decode_en_s : public functor_s { bool decode_en; // This is the enable that arrives from the extra input. bool extra_en; + // This is the mass-enable that enables independent of address + bool mass_en; }; vvp_decode_adr_s::vvp_decode_adr_s(vvp_ipoint_t me, unsigned w) @@ -119,6 +121,7 @@ vvp_decode_en_s::vvp_decode_en_s(vvp_decode_adr_s*dec, unsigned s) enable_next = 0; decode_en = false; extra_en = true; + mass_en = false; decoder = dec; enable_next = decoder->enable_list; @@ -132,13 +135,25 @@ void vvp_decode_en_s::set(vvp_ipoint_t i, bool push, ifu->put(i, val); int abval = functor_get_input(i); - if (abval == 1) { - extra_en = true; - } else { - extra_en = false; + unsigned port = ipoint_port(i); + switch (port) { + case 0: // regular enable + if (abval == 1) { + extra_en = true; + } else { + extra_en = false; + } + break; + case 1: // mass enable + if (abval == 1) { + mass_en = true; + } else { + mass_en = false; + } + break; } - if (extra_en && decode_en) + if (extra_en && decode_en || mass_en) put_oval(1, true); else put_oval(0, true); @@ -183,7 +198,8 @@ void compile_decode_adr(char*label, unsigned argc, struct symb_s*argv) } void compile_decode_en(char*label, char*decoder, int slice, - struct symb_s enable) + struct symb_s enable, + struct symb_s mass_enable) { vvp_decode_adr_s*adr = decoder_find(decoder); vvp_decode_en_s*a = new struct vvp_decode_en_s(adr, slice); @@ -191,9 +207,10 @@ void compile_decode_en(char*label, char*decoder, int slice, vvp_ipoint_t ix = functor_allocate(1); functor_define(ix, a); - if (enable.text) { - inputs_connect(ix, 1, &enable); - } + symb_s argv[2]; + argv[0] = enable; + argv[1] = mass_enable; + inputs_connect(ix, 2, argv); define_functor_symbol(label, ix); free(label); @@ -201,6 +218,9 @@ void compile_decode_en(char*label, char*decoder, int slice, /* * $Log: decoder.cc,v $ + * Revision 1.1.2.2 2006/03/12 07:34:21 steve + * Fix the memsynth1 case. + * * Revision 1.1.2.1 2006/02/19 00:11:36 steve * Handle synthesis of FF vectors with l-value decoder. * diff --git a/vvp/parse.y b/vvp/parse.y index 41b031d0a..1b7563e07 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: parse.y,v 1.60.2.1 2006/02/19 00:11:36 steve Exp $" +#ident "$Id: parse.y,v 1.60.2.2 2006/03/12 07:34:21 steve Exp $" #endif # include "parse_misc.h" @@ -270,8 +270,8 @@ statement compile_decode_adr($1, obj.cnt, obj.vect); } - | T_LABEL K_DECODE_EN T_SYMBOL ',' T_NUMBER ',' symbol ';' - { compile_decode_en($1, $3, $5, $7); + | T_LABEL K_DECODE_EN T_SYMBOL ',' T_NUMBER ',' symbol ',' symbol ';' + { compile_decode_en($1, $3, $5, $7, $9); } /* Event statements take a label, a type (the first T_SYMBOL) and a @@ -646,6 +646,9 @@ int compile_design(const char*path) /* * $Log: parse.y,v $ + * Revision 1.60.2.2 2006/03/12 07:34:21 steve + * Fix the memsynth1 case. + * * Revision 1.60.2.1 2006/02/19 00:11:36 steve * Handle synthesis of FF vectors with l-value decoder. *