From 89881adece3d3849fe3011bd7c2fddb40e31d1bd Mon Sep 17 00:00:00 2001 From: steve Date: Mon, 1 Nov 1999 02:07:40 +0000 Subject: [PATCH] Add the synth functor to do generic synthesis and add the LPM_FF device to handle rows of flip-flops. --- Makefile.in | 4 +- design_dump.cc | 14 ++- emit.cc | 12 ++- functor.cc | 31 +++++- functor.h | 9 +- lpm.txt | 26 ++++++ main.cc | 9 +- netlist.cc | 124 +++++++++++++++++++++++- netlist.h | 40 +++++++- synth.cc | 244 ++++++++++++++++++++++++++++++++++++++++++++++++ t-vvm.cc | 23 ++++- target.cc | 13 ++- target.h | 8 +- vvm/vvm.h | 10 +- vvm/vvm_bit.cc | 21 ++++- vvm/vvm_gates.h | 57 ++++++++++- 16 files changed, 629 insertions(+), 16 deletions(-) create mode 100644 lpm.txt create mode 100644 synth.cc diff --git a/Makefile.in b/Makefile.in index 879630141..e09054187 100644 --- a/Makefile.in +++ b/Makefile.in @@ -18,7 +18,7 @@ # 59 Temple Place - Suite 330 # Boston, MA 02111-1307, USA # -#ident "$Id: Makefile.in,v 1.25 1999/10/31 20:08:24 steve Exp $" +#ident "$Id: Makefile.in,v 1.26 1999/11/01 02:07:40 steve Exp $" # # SHELL = /bin/sh @@ -66,7 +66,7 @@ distclean: clean rm -f Makefile TT = t-null.o t-verilog.o t-vvm.o t-xnf.o -FF = nobufz.o propinit.o sigfold.o xnfio.o xnfsyn.o +FF = nobufz.o propinit.o sigfold.o synth.o xnfio.o xnfsyn.o O = main.o cprop.o design_dump.o elaborate.o elab_expr.o elab_net.o \ emit.o eval.o eval_tree.o functor.o \ diff --git a/design_dump.cc b/design_dump.cc index 0e303bc48..f562833a8 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 */ #if !defined(WINNT) -#ident "$Id: design_dump.cc,v 1.52 1999/10/31 20:08:24 steve Exp $" +#ident "$Id: design_dump.cc,v 1.53 1999/11/01 02:07:40 steve Exp $" #endif /* @@ -168,6 +168,13 @@ void NetConst::dump_node(ostream&o, unsigned ind) const dump_node_pins(o, ind+4); } +void NetFF::dump_node(ostream&o, unsigned ind) const +{ + o << setw(ind) << "" << "LPM_FF: " << name() << endl; + dump_node_pins(o, ind+4); + dump_obj_attr(o, ind+4); +} + void NetLogic::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << "logic: "; @@ -798,6 +805,11 @@ void Design::dump(ostream&o) const /* * $Log: design_dump.cc,v $ + * Revision 1.53 1999/11/01 02:07:40 steve + * Add the synth functor to do generic synthesis + * and add the LPM_FF device to handle rows of + * flip-flops. + * * Revision 1.52 1999/10/31 20:08:24 steve * Include subtraction in LPM_ADD_SUB device. * diff --git a/emit.cc b/emit.cc index 33ead0613..d55319d9c 100644 --- a/emit.cc +++ b/emit.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: emit.cc,v 1.24 1999/10/10 01:59:54 steve Exp $" +#ident "$Id: emit.cc,v 1.25 1999/11/01 02:07:40 steve Exp $" #endif /* @@ -70,6 +70,11 @@ void NetConst::emit_node(ostream&o, struct target_t*tgt) const tgt->net_const(o, this); } +void NetFF::emit_node(ostream&o, struct target_t*tgt) const +{ + tgt->lpm_ff(o, this); +} + void NetNEvent::emit_node(ostream&o, struct target_t*tgt) const { tgt->net_event(o, this); @@ -357,6 +362,11 @@ bool emit(ostream&o, const Design*des, const char*type) /* * $Log: emit.cc,v $ + * Revision 1.25 1999/11/01 02:07:40 steve + * Add the synth functor to do generic synthesis + * and add the LPM_FF device to handle rows of + * flip-flops. + * * Revision 1.24 1999/10/10 01:59:54 steve * Structural case equals device. * diff --git a/functor.cc b/functor.cc index d7aee8e1b..2c88ce50f 100644 --- a/functor.cc +++ b/functor.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: functor.cc,v 1.2 1999/07/18 05:52:46 steve Exp $" +#ident "$Id: functor.cc,v 1.3 1999/11/01 02:07:40 steve Exp $" #endif # include "functor.h" @@ -35,6 +35,10 @@ void functor_t::process(class Design*, class NetProcTop*) { } +void functor_t::lpm_ff(class Design*, class NetFF*) +{ +} + void Design::functor(functor_t*fun) { // apply to signals @@ -53,10 +57,35 @@ void Design::functor(functor_t*fun) procs_idx_ = idx->next_; fun->process(this, idx); } + + // apply to nodes + if (nodes_) { + NetNode*cur = nodes_->node_next_; + do { + NetNode*tmp = cur->node_next_; + cur->functor_node(this, fun); + cur = tmp; + } while (cur != nodes_->node_next_); + } +} + + +void NetNode::functor_node(Design*, functor_t*) +{ +} + +void NetFF::functor_node(Design*des, functor_t*fun) +{ + fun->lpm_ff(des, this); } /* * $Log: functor.cc,v $ + * Revision 1.3 1999/11/01 02:07:40 steve + * Add the synth functor to do generic synthesis + * and add the LPM_FF device to handle rows of + * flip-flops. + * * Revision 1.2 1999/07/18 05:52:46 steve * xnfsyn generates DFF objects for XNF output, and * properly rewrites the Design netlist in the process. diff --git a/functor.h b/functor.h index 3882a4dd6..e3f549ab2 100644 --- a/functor.h +++ b/functor.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: functor.h,v 1.1 1999/07/17 22:01:13 steve Exp $" +#ident "$Id: functor.h,v 1.2 1999/11/01 02:07:40 steve Exp $" #endif /* @@ -42,10 +42,17 @@ struct functor_t { /* This method is called for each process in the design. */ virtual void process(class Design*des, class NetProcTop*); + /* This method is called for each FF in the design. */ + virtual void lpm_ff(class Design*des, class NetFF*); }; /* * $Log: functor.h,v $ + * Revision 1.2 1999/11/01 02:07:40 steve + * Add the synth functor to do generic synthesis + * and add the LPM_FF device to handle rows of + * flip-flops. + * * Revision 1.1 1999/07/17 22:01:13 steve * Add the functor interface for functor transforms. * diff --git a/lpm.txt b/lpm.txt new file mode 100644 index 000000000..a3d5665b3 --- /dev/null +++ b/lpm.txt @@ -0,0 +1,26 @@ + +WHAT IS LPM + +LPM (Library of Paramaterized Modules) is EIS-IS standard 103-A. It is +a standard library of abstract devices that are designed to be close +enough to the target hardware to be easily translated, yet abstract +enough to support a variety of target technologies without excessive +constraints. Icarus Verilog uses LPM internally to represent idealized +hardware, especially when doing target neutral synthesis. + +In general, the user does not even see the LPM that Icarus Verilog +generates, because the LPM devices are translated into technology +specific devices by the final code generator or target specific +optimizers. + +INTERNAL USES OF LPM + +Internally, Icarus Verilog uses LPM devices to represent the design in +abstract, especially when synthesizing such functions as addition, +flip-flops, etc. The ``synth'' functor generates LPM modules when +interpreting procedural constructs. The functor generates the LPM +objects needed to replace a behavioral description, and uses +attributes to tag the devices with LPM properties. + +Code generators need to understand the supported LPM devices so that +they can translate the devices into technology specific devices. diff --git a/main.cc b/main.cc index 33e634893..9871037d9 100644 --- a/main.cc +++ b/main.cc @@ -19,7 +19,7 @@ const char COPYRIGHT[] = * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: main.cc,v 1.23 1999/09/22 16:57:23 steve Exp $" +#ident "$Id: main.cc,v 1.24 1999/11/01 02:07:40 steve Exp $" #endif const char NOTICE[] = @@ -79,6 +79,7 @@ extern Design* elaborate(const map&modules, extern void cprop(Design*des); extern void propinit(Design*des); extern void sigfold(Design*des); +extern void synth(Design*des); extern void nobufz(Design*des); extern void xnfio(Design*des); extern void xnfsyn(Design*des); @@ -92,6 +93,7 @@ static struct net_func_map { { "nobufz", &nobufz }, { "propinit", &propinit }, { "sigfold", &sigfold }, + { "synth", &synth }, { "xnfio", &xnfio }, { "xnfsyn", &xnfsyn }, { 0, 0 } @@ -277,6 +279,11 @@ int main(int argc, char*argv[]) /* * $Log: main.cc,v $ + * Revision 1.24 1999/11/01 02:07:40 steve + * Add the synth functor to do generic synthesis + * and add the LPM_FF device to handle rows of + * flip-flops. + * * Revision 1.23 1999/09/22 16:57:23 steve * Catch parallel blocks in vvm emit. * diff --git a/netlist.cc b/netlist.cc index 940cce9e4..ff0329187 100644 --- a/netlist.cc +++ b/netlist.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: netlist.cc,v 1.78 1999/10/31 04:11:27 steve Exp $" +#ident "$Id: netlist.cc,v 1.79 1999/11/01 02:07:40 steve Exp $" #endif # include @@ -376,7 +376,122 @@ const NetProc* NetProcTop::statement() const } /* - * The NetAddSub class represents an LPM ADD_SUB device. The pinout is + * The NetFF class represents an LPM_FF device. The pinout is assigned + * like so: + * 0 -- Clock + * 1 -- Enable + * 2 -- Aload + * 3 -- Aset + * 4 -- Aclr + * 5 -- Sload + * 6 -- Sset + * 7 -- Sclr + * + * 8 -- Data[0] + * 9 -- Q[0] + * ... + */ + +NetFF::NetFF(const string&n, unsigned wid) +: NetNode(n, 8 + 2*wid) +{ + pin_Clock().set_dir(Link::INPUT); + pin_Clock().set_name("Clock", 0); + pin_Enable().set_dir(Link::INPUT); + pin_Enable().set_name("Enable", 0); + pin_Aload().set_dir(Link::INPUT); + pin_Aload().set_name("Aload", 0); + pin_Aset().set_dir(Link::INPUT); + pin_Aset().set_name("Aset", 0); + pin_Aclr().set_dir(Link::INPUT); + pin_Aclr().set_name("Aclr", 0); + pin_Sload().set_dir(Link::INPUT); + pin_Sload().set_name("Sload", 0); + pin_Sset().set_dir(Link::INPUT); + pin_Sset().set_name("Sset", 0); + pin_Sclr().set_dir(Link::INPUT); + pin_Sclr().set_name("Sclr", 0); + for (unsigned idx = 0 ; idx < wid ; idx += 1) { + pin_Data(idx).set_dir(Link::INPUT); + pin_Data(idx).set_name("Data", idx); + pin_Q(idx).set_dir(Link::OUTPUT); + pin_Q(idx).set_name("Q", idx); + } +} + +NetFF::~NetFF() +{ +} + +unsigned NetFF::width() const +{ + return (pin_count() - 8) / 2; +} + +NetObj::Link& NetFF::pin_Clock() +{ + return pin(0); +} + +NetObj::Link& NetFF::pin_Enable() +{ + return pin(1); +} + +NetObj::Link& NetFF::pin_Aload() +{ + return pin(2); +} + +NetObj::Link& NetFF::pin_Aset() +{ + return pin(3); +} + +NetObj::Link& NetFF::pin_Aclr() +{ + return pin(4); +} + +NetObj::Link& NetFF::pin_Sload() +{ + return pin(5); +} + +NetObj::Link& NetFF::pin_Sset() +{ + return pin(6); +} + +NetObj::Link& NetFF::pin_Sclr() +{ + return pin(7); +} + +NetObj::Link& NetFF::pin_Data(unsigned w) +{ + unsigned pn = 8 + 2*w; + assert(pn < pin_count()); + return pin(pn); +} + +NetObj::Link& NetFF::pin_Q(unsigned w) +{ + unsigned pn = 9 + w*2; + assert(pn < pin_count()); + return pin(pn); +} + +const NetObj::Link& NetFF::pin_Q(unsigned w) const +{ + unsigned pn = 9 + w*2; + assert(pn < pin_count()); + return pin(pn); +} + + +/* + * The NetAddSub class represents an LPM_ADD_SUB device. The pinout is * assigned like so: * 0 -- Add_Sub * 1 -- Aclr @@ -1878,6 +1993,11 @@ NetNet* Design::find_signal(bool (*func)(const NetNet*)) /* * $Log: netlist.cc,v $ + * Revision 1.79 1999/11/01 02:07:40 steve + * Add the synth functor to do generic synthesis + * and add the LPM_FF device to handle rows of + * flip-flops. + * * Revision 1.78 1999/10/31 04:11:27 steve * Add to netlist links pin name and instance number, * and arrange in vvm for pin connections by name diff --git a/netlist.h b/netlist.h index d3a8bd8e4..07b25b515 100644 --- a/netlist.h +++ b/netlist.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: netlist.h,v 1.81 1999/10/31 04:11:27 steve Exp $" +#ident "$Id: netlist.h,v 1.82 1999/11/01 02:07:40 steve Exp $" #endif /* @@ -211,6 +211,8 @@ class NetNode : public NetObj { virtual void emit_node(ostream&, struct target_t*) const; virtual void dump_node(ostream&, unsigned) const; + virtual void functor_node(Design*, functor_t*); + private: friend class Design; NetNode*node_next_, *node_prev_; @@ -321,6 +323,37 @@ class NetAddSub : public NetNode { virtual void emit_node(ostream&, struct target_t*) const; }; +/* + * This class represents an LPM_FF device. There is no literal gate + * type in Verilog that maps, but gates of this type can be inferred. + */ +class NetFF : public NetNode { + + public: + NetFF(const string&n, unsigned width); + ~NetFF(); + + unsigned width() const; + + NetObj::Link& pin_Clock(); + NetObj::Link& pin_Enable(); + NetObj::Link& pin_Aload(); + NetObj::Link& pin_Aset(); + NetObj::Link& pin_Aclr(); + NetObj::Link& pin_Sload(); + NetObj::Link& pin_Sset(); + NetObj::Link& pin_Sclr(); + + NetObj::Link& pin_Data(unsigned); + NetObj::Link& pin_Q(unsigned); + + const NetObj::Link& pin_Q(unsigned) const; + + virtual void dump_node(ostream&, unsigned ind) const; + virtual void emit_node(ostream&, struct target_t*) const; + virtual void functor_node(Design*des, functor_t*fun); +}; + /* * This class represents the declared memory object. The parser * creates one of these for each declared memory in the elaborated @@ -1749,6 +1782,11 @@ extern ostream& operator << (ostream&, NetNet::Type); /* * $Log: netlist.h,v $ + * Revision 1.82 1999/11/01 02:07:40 steve + * Add the synth functor to do generic synthesis + * and add the LPM_FF device to handle rows of + * flip-flops. + * * Revision 1.81 1999/10/31 04:11:27 steve * Add to netlist links pin name and instance number, * and arrange in vvm for pin connections by name diff --git a/synth.cc b/synth.cc new file mode 100644 index 000000000..d2c9a9bb9 --- /dev/null +++ b/synth.cc @@ -0,0 +1,244 @@ +/* + * Copyright (c) 1999 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ +#if !defined(WINNT) +#ident "$Id: synth.cc,v 1.1 1999/11/01 02:07:41 steve Exp $" +#endif + +/* + * The synth function searches the behavioral description for + * patterns that are known to represent LPM library components. This + * is especially interesting for the sequential components such as + * flip flops and latches. As threads are transformed into components, + * the design is rewritten. + * + * Currently, this transform recognizes the following patterns: + * + * always @(posedge CLK) Q = D + * always @(negedge CLK) Q = D + * + * always @(posedge CLK) if (CE) Q = D; + * always @(negedge CLK) if (CE) Q = D; + * + * The r-value of the assignments must be identifiers (i.e. wires or + * registers) and the CE must be single-bit identifiers. The generated + * device will be wide enough to accomodate Q and D. + */ +# include "functor.h" +# include "netlist.h" + +class synth_f : public functor_t { + + public: + void process(class Design*, class NetProcTop*); + + private: + void proc_always_(class Design*); + void proc_casn_(class Design*); + void proc_ccon_(class Design*); + + // The matcher does something like a recursive descent search + // for the templates. These variables are filled in as the + // searcher finds them. + + class NetProcTop*top_; + + class NetPEvent *pclk_; + class NetNEvent *nclk_; + + class NetCondit *con_; + class NetAssign *asn_; +}; + + +/* + * Look at a process, and divide the problem into always and initial + * threads. + */ +void synth_f::process(class Design*des, class NetProcTop*top) +{ + switch (top->type()) { + case NetProcTop::KALWAYS: + top_ = top; + proc_always_(des); + break; + } +} + +/* + * An "always ..." statement has been found. + */ +void synth_f::proc_always_(class Design*des) +{ + // The statement must be a NetPEvent, ... + pclk_ = dynamic_cast(top_->statement()); + if (pclk_ == 0) + return; + + // ... there must be a single event source, ... + svector*neb = pclk_->back_list(); + if (neb == 0) + return; + if (neb->count() != 1) { + delete neb; + return; + } + nclk_ = (*neb)[0]; + delete neb; + + // ... the event must be an edge, ... + switch (nclk_->type()) { + case NetNEvent::POSEDGE: + case NetNEvent::NEGEDGE: + break; + default: + return; + } + + // Is this a clocked assignment? + asn_ = dynamic_cast(pclk_->statement()); + if (asn_) { + proc_casn_(des); + return; + } + + con_ = dynamic_cast(pclk_->statement()); + if (con_) { + proc_ccon_(des); + return; + } +} + +/* + * The process so far has been matched as: + * + * always @(posedge nclk_) asn_ = ; + * always @(negedge nclk_) asn_ = ; + */ +void synth_f::proc_casn_(class Design*des) +{ + + // ... and the rval must be a simple signal. + NetESignal*sig = dynamic_cast(asn_->rval()); + if (sig == 0) { + cerr << "Noted complex rval in DFF, name " << asn_->name() << + ", not yet implemented" << endl; + return ; + } + + // The signal and the assignment must be the same width... + assert(asn_->pin_count() == sig->pin_count()); + + NetFF*ff = new NetFF(asn_->name(), asn_->pin_count()); + ff->attribute("LPM_FFType", "DFF"); + + for (unsigned idx = 0 ; idx < ff->width() ; idx += 1) { + connect(ff->pin_Data(idx), sig->pin(idx)); + connect(ff->pin_Q(idx), asn_->pin(idx)); + } + + switch (nclk_->type()) { + case NetNEvent::POSEDGE: + connect(ff->pin_Clock(), nclk_->pin(0)); + break; + + case NetNEvent::NEGEDGE: + connect(ff->pin_Clock(), nclk_->pin(0)); + ff->attribute("Clock:LPM_Polarity", "INVERT"); + break; + } + + des->add_node(ff); + + // This process is matched and replaced with a DFF. Get + // rid of the now useless NetProcTop. + des->delete_process(top_); +} + +/* + * The process so far has been matched as: + * + * always @(posedge nclk_) if ...; + * always @(negedge nclk_) if ...; + */ +void synth_f::proc_ccon_(class Design*des) +{ + if (con_->else_clause()) + return; + + asn_ = dynamic_cast(con_->if_clause()); + if (asn_ == 0) + return; + + NetESignal*sig = dynamic_cast(asn_->rval()); + if (sig == 0) + return; + + // The signal and the assignment must be the same width... + assert(asn_->pin_count() == sig->pin_count()); + + NetESignal*ce = dynamic_cast(con_->expr()); + if (ce == 0) + return; + if (ce->pin_count() != 1) + return; + + NetFF*ff = new NetFF(asn_->name(), asn_->pin_count()); + ff->attribute("LPM_FFType", "DFF"); + + for (unsigned idx = 0 ; idx < ff->width() ; idx += 1) { + connect(ff->pin_Data(idx), sig->pin(idx)); + connect(ff->pin_Q(idx), asn_->pin(idx)); + } + + switch (nclk_->type()) { + case NetNEvent::POSEDGE: + connect(ff->pin_Clock(), nclk_->pin(0)); + connect(ff->pin_Enable(), ce->pin(0)); + break; + + case NetNEvent::NEGEDGE: + connect(ff->pin_Clock(), nclk_->pin(0)); + connect(ff->pin_Enable(), ce->pin(0)); + ff->attribute("Clock:LPM_Polarity", "INVERT"); + break; + } + + des->add_node(ff); + + + // This process is matched and replaced with a DFF. Get + // rid of the now useless NetProcTop. + des->delete_process(top_); +} + +void synth(Design*des) +{ + synth_f synth_obj; + des->functor(&synth_obj); +} + +/* + * $Log: synth.cc,v $ + * Revision 1.1 1999/11/01 02:07:41 steve + * Add the synth functor to do generic synthesis + * and add the LPM_FF device to handle rows of + * flip-flops. + * + */ + diff --git a/t-vvm.cc b/t-vvm.cc index 067846363..f5e740d4a 100644 --- a/t-vvm.cc +++ b/t-vvm.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: t-vvm.cc,v 1.70 1999/10/31 20:08:24 steve Exp $" +#ident "$Id: t-vvm.cc,v 1.71 1999/11/01 02:07:41 steve Exp $" #endif # include @@ -53,6 +53,7 @@ class target_vvm : public target_t { virtual void func_def(ostream&os, const NetFuncDef*); virtual void lpm_add_sub(ostream&os, const NetAddSub*); + virtual void lpm_ff(ostream&os, const NetFF*); virtual void logic(ostream&os, const NetLogic*); virtual void bufz(ostream&os, const NetBUFZ*); @@ -835,6 +836,21 @@ void target_vvm::lpm_add_sub(ostream&os, const NetAddSub*gate) } } +void target_vvm::lpm_ff(ostream&os, const NetFF*gate) +{ + string mname = mangle(gate->name()); + os << "static vvm_ff<" << gate->width() << "> " << mname << ";" + << endl; + + for (unsigned idx = 0 ; idx < gate->width() ; idx += 1) { + unsigned pin = gate->pin_Q(idx).get_pin(); + string outfun = defn_gate_outputfun_(os, gate, pin); + init_code << " " << mangle(gate->name()) << + ".config_rout(" << idx << ", &" << outfun << ");" << endl; + emit_gate_outputfun_(gate, pin); + } +} + void target_vvm::logic(ostream&os, const NetLogic*gate) { string outfun = defn_gate_outputfun_(os, gate, 0); @@ -1802,6 +1818,11 @@ extern const struct target tgt_vvm = { }; /* * $Log: t-vvm.cc,v $ + * Revision 1.71 1999/11/01 02:07:41 steve + * Add the synth functor to do generic synthesis + * and add the LPM_FF device to handle rows of + * flip-flops. + * * Revision 1.70 1999/10/31 20:08:24 steve * Include subtraction in LPM_ADD_SUB device. * diff --git a/target.cc b/target.cc index 524eafc29..70b872bef 100644 --- a/target.cc +++ b/target.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: target.cc,v 1.21 1999/10/10 01:59:55 steve Exp $" +#ident "$Id: target.cc,v 1.22 1999/11/01 02:07:41 steve Exp $" #endif # include "target.h" @@ -75,6 +75,12 @@ void target_t::lpm_add_sub(ostream&, const NetAddSub*) "Unhandled NetAddSub." << endl; } +void target_t::lpm_ff(ostream&, const NetFF*) +{ + cerr << "target (" << typeid(*this).name() << "): " + "Unhandled NetFF." << endl; +} + void target_t::net_assign(ostream&os, const NetAssign*) { } @@ -275,6 +281,11 @@ void expr_scan_t::expr_binary(const NetEBinary*ex) /* * $Log: target.cc,v $ + * Revision 1.22 1999/11/01 02:07:41 steve + * Add the synth functor to do generic synthesis + * and add the LPM_FF device to handle rows of + * flip-flops. + * * Revision 1.21 1999/10/10 01:59:55 steve * Structural case equals device. * diff --git a/target.h b/target.h index 688a3d380..e19398ca2 100644 --- a/target.h +++ b/target.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: target.h,v 1.20 1999/10/10 01:59:55 steve Exp $" +#ident "$Id: target.h,v 1.21 1999/11/01 02:07:41 steve Exp $" #endif # include "netlist.h" @@ -67,6 +67,7 @@ struct target_t { /* LPM style components are handled here. */ virtual void lpm_add_sub(ostream&os, const NetAddSub*); + virtual void lpm_ff(ostream&os, const NetFF*); /* Output a gate (called for each gate) */ virtual void logic(ostream&os, const NetLogic*); @@ -137,6 +138,11 @@ extern const struct target *target_table[]; /* * $Log: target.h,v $ + * Revision 1.21 1999/11/01 02:07:41 steve + * Add the synth functor to do generic synthesis + * and add the LPM_FF device to handle rows of + * flip-flops. + * * Revision 1.20 1999/10/10 01:59:55 steve * Structural case equals device. * diff --git a/vvm/vvm.h b/vvm/vvm.h index 5888560c8..13a0f3f4c 100644 --- a/vvm/vvm.h +++ b/vvm/vvm.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: vvm.h,v 1.19 1999/10/31 04:11:28 steve Exp $" +#ident "$Id: vvm.h,v 1.20 1999/11/01 02:07:41 steve Exp $" #endif # include @@ -98,6 +98,9 @@ inline vpip_bit_t not(vpip_bit_t l) } } +extern bool posedge(vpip_bit_t from, vpip_bit_t to); + + class vvm_bits_t { public: virtual ~vvm_bits_t() =0; @@ -253,6 +256,11 @@ template class vvm_signal_t : public __vpiSignal { /* * $Log: vvm.h,v $ + * Revision 1.20 1999/11/01 02:07:41 steve + * Add the synth functor to do generic synthesis + * and add the LPM_FF device to handle rows of + * flip-flops. + * * Revision 1.19 1999/10/31 04:11:28 steve * Add to netlist links pin name and instance number, * and arrange in vvm for pin connections by name diff --git a/vvm/vvm_bit.cc b/vvm/vvm_bit.cc index 08c8619cf..cace5c1f0 100644 --- a/vvm/vvm_bit.cc +++ b/vvm/vvm_bit.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: vvm_bit.cc,v 1.3 1999/10/28 00:47:25 steve Exp $" +#ident "$Id: vvm_bit.cc,v 1.4 1999/11/01 02:07:41 steve Exp $" #endif # include "vvm.h" @@ -41,6 +41,20 @@ ostream& operator << (ostream&os, vpip_bit_t bit) return os; } +bool posedge(vpip_bit_t from, vpip_bit_t to) +{ + switch (from) { + case V1: + return false; + case V0: + return from != to; + case Vx: + case Vz: + return to == V1; + } + return false; +} + ostream& operator << (ostream&os, const vvm_bits_t&str) { os << str.get_width() << "b'"; @@ -100,6 +114,11 @@ vpip_bit_t add_with_carry(vpip_bit_t l, vpip_bit_t r, vpip_bit_t&carry) /* * $Log: vvm_bit.cc,v $ + * Revision 1.4 1999/11/01 02:07:41 steve + * Add the synth functor to do generic synthesis + * and add the LPM_FF device to handle rows of + * flip-flops. + * * Revision 1.3 1999/10/28 00:47:25 steve * Rewrite vvm VPI support to make objects more * persistent, rewrite the simulation scheduler diff --git a/vvm/vvm_gates.h b/vvm/vvm_gates.h index ee624b2d3..e1c2f9c54 100644 --- a/vvm/vvm_gates.h +++ b/vvm/vvm_gates.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: vvm_gates.h,v 1.17 1999/10/31 20:08:24 steve Exp $" +#ident "$Id: vvm_gates.h,v 1.18 1999/11/01 02:07:41 steve Exp $" #endif # include "vvm.h" @@ -152,6 +152,56 @@ template class vvm_and { vvm_out_event::action_t output_; }; +/* + * This class simulates the LPM flip-flop device. + * XXXX Inverted clock not yet supported. + */ +template class vvm_ff { + + public: + explicit vvm_ff() + { clk_ = Vx; + for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) + q_[idx] = Vx; + } + ~vvm_ff() { } + + void init_Data(unsigned idx, vpip_bit_t val) { d_[idx] = val; } + void init_Clock(unsigned, vpip_bit_t val) { clk_ = val; } + + void set_Clock(vvm_simulation*sim, unsigned, vpip_bit_t val) + { if (val == clk_) return; + bool flag = posedge(clk_, val); + clk_ = val; + if (flag) latch_(sim); + } + + void set_Data(vvm_simulation*sim, unsigned idx, vpip_bit_t val) + { d_[idx] = val; + } + + void config_rout(unsigned idx, vvm_out_event::action_t o) + { out_[idx] = o; + } + + private: + vpip_bit_t d_[WIDTH]; + vpip_bit_t q_[WIDTH]; + vpip_bit_t clk_; + + vvm_out_event::action_t out_[WIDTH]; + + void latch_(vvm_simulation*sim) + { q_ = d_; + for (unsigned idx = 0 ; idx < WIDTH ; idx += 1) + if (out_[idx]) { + vvm_event*ev = new vvm_out_event(sim, q_[idx], + out_[idx]); + sim->active_event(ev); + } + } +}; + template class vvm_or { public: @@ -599,6 +649,11 @@ template class vvm_pevent { /* * $Log: vvm_gates.h,v $ + * Revision 1.18 1999/11/01 02:07:41 steve + * Add the synth functor to do generic synthesis + * and add the LPM_FF device to handle rows of + * flip-flops. + * * Revision 1.17 1999/10/31 20:08:24 steve * Include subtraction in LPM_ADD_SUB device. *