diff --git a/elaborate.cc b/elaborate.cc index e6ace5c45..d7663ff64 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: elaborate.cc,v 1.57 1999/07/17 19:50:59 steve Exp $" +#ident "$Id: elaborate.cc,v 1.58 1999/07/18 21:17:50 steve Exp $" #endif /* @@ -987,7 +987,6 @@ NetExpr*PEIdent::elaborate_expr(Design*des, const string&path) const connect(tmp->pin(idx), net->pin(idx+lsv)); des->add_node(tmp); - des->set_esignal(tmp); return tmp; } @@ -1005,11 +1004,11 @@ NetExpr*PEIdent::elaborate_expr(Design*des, const string&path) const connect(tmp->pin(0), net->pin(msv)); des->add_node(tmp); - des->set_esignal(tmp); return tmp; } - NetESignal*node = des->get_esignal(net); + NetESignal*node = new NetESignal(net); + des->add_node(node); assert(idx_ == 0); // Non-constant bit select? punt and make a subsignal @@ -1258,7 +1257,8 @@ NetProc* PAssign::elaborate(Design*des, const string&path) const connect(a1->pin(idx), tmp->pin(idx)); n = des->local_symbol(path); - NetESignal*sig = des->get_esignal(tmp); + NetESignal*sig = new NetESignal(tmp); + des->add_node(sig); NetAssign*a2 = new NetAssign(n, des, wid, sig); a2->set_line(*this); des->add_node(a2); @@ -1862,6 +1862,10 @@ Design* elaborate(const map&modules, /* * $Log: elaborate.cc,v $ + * Revision 1.58 1999/07/18 21:17:50 steve + * Add support for CE input to XNF DFF, and do + * complete cleanup of replaced design nodes. + * * Revision 1.57 1999/07/17 19:50:59 steve * netlist support for ternary operator. * diff --git a/netlist.cc b/netlist.cc index 59c18b5dc..4d82caa69 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.46 1999/07/18 05:52:46 steve Exp $" +#ident "$Id: netlist.cc,v 1.47 1999/07/18 21:17:50 steve Exp $" #endif # include @@ -283,6 +283,16 @@ NetProcTop::~NetProcTop() delete statement_; } +NetProc* NetProcTop::statement() +{ + return statement_; +} + +const NetProc* NetProcTop::statement() const +{ + return statement_; +} + NetAssign_::NetAssign_(const string&n, unsigned w) : NetNode(n, w) { @@ -309,6 +319,7 @@ NetAssign::NetAssign(const string&n, Design*des, unsigned w, NetExpr*rv) NetAssign::~NetAssign() { + delete rval_; } NetAssignNB::NetAssignNB(const string&n, Design*des, unsigned w, NetExpr*rv) @@ -441,6 +452,33 @@ NetCondit::NetCondit(NetExpr*ex, NetProc*i, NetProc*e) { } +NetCondit::~NetCondit() +{ + delete expr_; + if (if_) delete if_; + if (else_) delete else_; +} + +const NetExpr* NetCondit::expr() const +{ + return expr_; +} + +NetExpr* NetCondit::expr() +{ + return expr_; +} + +NetProc* NetCondit::if_clause() +{ + return if_; +} + +NetProc* NetCondit::else_clause() +{ + return else_; +} + NetNEvent::NetNEvent(const string&ev, unsigned wid, Type e, NetPEvent*pe) : NetNode(ev, wid), sref(pe), edge_(e) { @@ -457,7 +495,7 @@ NetPEvent::NetPEvent(const string&n, NetProc*st) NetPEvent::~NetPEvent() { - svector*back = back_list(); + svector*back = back_list(); if (back) { for (unsigned idx = 0 ; idx < back->count() ; idx += 1) { NetNEvent*ne = (*back)[idx]; @@ -465,6 +503,13 @@ NetPEvent::~NetPEvent() } delete back; } + + delete statement_; +} + +NetProc* NetPEvent::statement() +{ + return statement_; } const NetProc* NetPEvent::statement() const @@ -1348,24 +1393,6 @@ void Design::del_node(NetNode*net) net->design_ = 0; } -NetESignal* Design::get_esignal(NetNet*net) -{ - NetESignal*&node = esigs_[net->name()]; - if (node == 0) { - node = new NetESignal(net); - add_node(node); - } - - return node; -} - -void Design::set_esignal(NetESignal*sig) -{ - NetESignal*&node = esigs_[sig->name()]; - assert( node == 0 ); - node = sig; -} - void Design::add_process(NetProcTop*pro) { pro->next_ = procs_; @@ -1452,6 +1479,10 @@ NetNet* Design::find_signal(bool (*func)(const NetNet*)) /* * $Log: netlist.cc,v $ + * Revision 1.47 1999/07/18 21:17:50 steve + * Add support for CE input to XNF DFF, and do + * complete cleanup of replaced design nodes. + * * Revision 1.46 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/netlist.h b/netlist.h index 917f79b28..d8dd49c12 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.49 1999/07/18 05:52:47 steve Exp $" +#ident "$Id: netlist.h,v 1.50 1999/07/18 21:17:50 steve Exp $" #endif /* @@ -581,6 +581,7 @@ class NetAssign : public NetAssign_ { explicit NetAssign(const string&, Design*des, unsigned w, NetExpr*rv); ~NetAssign(); + NetExpr*rval() { return rval_; } const NetExpr*rval() const { return rval_; } void find_lval_range(const NetNet*&net, unsigned&msb, @@ -715,8 +716,14 @@ class NetCondit : public NetProc { public: explicit NetCondit(NetExpr*ex, NetProc*i, NetProc*e); + ~NetCondit(); + + const NetExpr*expr() const; + NetExpr*expr(); + + NetProc* if_clause(); + NetProc* else_clause(); - const NetExpr*expr() const { return expr_; } void emit_recurse_if(ostream&, struct target_t*) const; void emit_recurse_else(ostream&, struct target_t*) const; @@ -783,6 +790,7 @@ class NetPEvent : public NetProc, public sref_back { ~NetPEvent(); string name() const { return name_; } + NetProc* statement(); const NetProc* statement() const; virtual void emit_proc(ostream&, struct target_t*) const; @@ -949,11 +957,12 @@ class NetProcTop : public LineInfo { public: enum Type { KINITIAL, KALWAYS }; - NetProcTop(Type t, NetProc*st); + NetProcTop(Type t, class NetProc*st); ~NetProcTop(); Type type() const { return type_; } - const NetProc*statement() const { return statement_; } + NetProc*statement(); + const NetProc*statement() const; void dump(ostream&, unsigned ind) const; void emit(ostream&, struct target_t*tgt) const; @@ -1274,10 +1283,6 @@ class Design { void add_node(NetNode*); void del_node(NetNode*); - // ESIGNALS - NetESignal* get_esignal(NetNet*net); - void set_esignal(NetESignal*sig); - // PROCESSES void add_process(NetProcTop*); void delete_process(NetProcTop*); @@ -1322,9 +1327,6 @@ class Design { map flags_; - // Use this map to prevent duplicate signals. - map esigs_; - unsigned lcounter_; private: // not implemented @@ -1374,6 +1376,10 @@ extern ostream& operator << (ostream&, NetNet::Type); /* * $Log: netlist.h,v $ + * Revision 1.50 1999/07/18 21:17:50 steve + * Add support for CE input to XNF DFF, and do + * complete cleanup of replaced design nodes. + * * Revision 1.49 1999/07/18 05:52:47 steve * xnfsyn generates DFF objects for XNF output, and * properly rewrites the Design netlist in the process. diff --git a/sref.h b/sref.h index 425588311..14d8afc6b 100644 --- a/sref.h +++ b/sref.h @@ -21,7 +21,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: sref.h,v 1.2 1999/07/18 05:52:47 steve Exp $" +#ident "$Id: sref.h,v 1.3 1999/07/18 21:17:51 steve Exp $" #endif # include @@ -45,6 +45,7 @@ template class sref_back { ~sref_back() { assert(sback_ == 0); } svector* back_list() const; + svector* back_list(); private: void desert_(sref*); @@ -101,6 +102,29 @@ svector* sref_back::back_list() const return result; } +template +svector* sref_back::back_list() +{ + if (sback_ == 0) return 0; + unsigned cnt = 1; + sref*cur = sback_->next_; + while (cur != sback_) { + cnt += 1; + cur = cur->next_; + } + + svector* result = new svector(cnt); + (*result)[0] = dynamic_cast(sback_); + cur = sback_->next_; + cnt = 1; + while (cur != sback_) { + (*result)[cnt] = dynamic_cast(cur); + cnt += 1; + cur = cur->next_; + } + return result; +} + template void sref_back::desert_(sref*item) { if (item == sback_) @@ -122,6 +146,10 @@ template void sref_back::desert_(sref*item) /* * $Log: sref.h,v $ + * Revision 1.3 1999/07/18 21:17:51 steve + * Add support for CE input to XNF DFF, and do + * complete cleanup of replaced design nodes. + * * Revision 1.2 1999/07/18 05:52:47 steve * xnfsyn generates DFF objects for XNF output, and * properly rewrites the Design netlist in the process. diff --git a/t-vvm.cc b/t-vvm.cc index 6502e8cd8..d5400f5e2 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.31 1999/07/17 03:39:11 steve Exp $" +#ident "$Id: t-vvm.cc,v 1.32 1999/07/18 21:17:51 steve Exp $" #endif # include @@ -77,6 +77,11 @@ class target_vvm : public target_t { ostrstream start_code; unsigned process_counter; unsigned thread_step_; + + // These methods are use to help prefent duplicate printouts + // of things that may be scanned multiple times. + mapesignal_printed_flag; + mappevent_printed_flag; }; @@ -790,6 +795,11 @@ void target_vvm::net_const(ostream&os, const NetConst*gate) void target_vvm::net_esignal(ostream&os, const NetESignal*net) { + bool&flag = esignal_printed_flag[net->name()]; + if (flag) + return; + + flag = true; os << "static vvm_bitset_t<" << net->pin_count() << "> " << mangle(net->name()) << "_bits; /* " << net->name() << " */" << endl; @@ -813,10 +823,11 @@ void target_vvm::net_event(ostream&os, const NetNEvent*gate) string pevent = mangle(gate->fore_ptr()->name()); os << " /* " << gate->name() << " */" << endl; - os << "#ifndef PEVENT_" << pevent << endl; - os << "#define PEVENT_" << pevent << endl; - os << "static vvm_sync " << pevent << ";" << endl; - os << "#endif" << endl; + bool&printed = pevent_printed_flag[pevent]; + if (! printed) { + printed = true; + os << "static vvm_sync " << pevent << ";" << endl; + } os << "static vvm_pevent<" << gate->pin_count() << "> " << mangle(gate->name()) << "(&" << pevent << ", "; @@ -1276,6 +1287,10 @@ extern const struct target tgt_vvm = { }; /* * $Log: t-vvm.cc,v $ + * Revision 1.32 1999/07/18 21:17:51 steve + * Add support for CE input to XNF DFF, and do + * complete cleanup of replaced design nodes. + * * Revision 1.31 1999/07/17 03:39:11 steve * simplified process scan for targets. * diff --git a/xnf.txt b/xnf.txt index 8434ed476..d1260711d 100644 --- a/xnf.txt +++ b/xnf.txt @@ -1,15 +1,49 @@ WHAT IS XNF -Xilinx Netlist Format. This is somewhat specific to the Xilinx tool -chain, but that is sufficiently ubiquitous that it is worth it. This -format can be fed to place and route tools and simulators. since third -party simulators accept XNF, the format may be useful even independent -of Xilinx parts. +XNF is the Xilinx Netlist Format. This is somewhat specific to the +Xilinx tool chain, but it is sufficiently ubiquitous that it's still +worth it. This format can be fed to place and route tools and +simulators. Since some third party simulators accept XNF, the format +may be useful even independent of Xilinx parts. -The xnfio function is highly recommended as it optimizes use of the IO -blocks. Without this function, the I/O blocks will probably remain -unused. +Icarus Verilog supports XNF as specified by the Xilinx Netlist Format +Specification, Version 6.1. + +IVL SUPPORT FOR XNF + +Icarus Verilog has a code generator and synthesis functions that +support generation of XNF netlists. The XNF modules also allow the +programmer to use $attributes to control certain aspects of code +generation. + +XNF code generation is enabled with the ``-t xnf'' flag on the command +line. The XNF code generator needs to know the type of part to +generate code for, so the ``-fpart='' flag is also needed. For +example, to generate code for the 4010E the command line might start +out as: + + ivl -txnf -fpart=4010e -Fxnfsyn -Fxnfio [...] + +Icarus Verilog includes the functions ``xnfsyn'' and ``xnfio'' to +perform transformations and optimizations on the design before code is +generated. The xnfsyn function matches certain behavioral constructs +to XNF components, and the xnfio function generates pads and fills the +IOBs. + +XNFSYN FUNCTION + +This function does synthesis transformations on the entered design, +making it possible to generate XNF netlist components from certain +behavioral constructs. This is needed in Verilog for example to model +some of the synchronous components of the XNF library. + +It is a bit much to expect a Verilog compiler in general to generate +components from arbitrary behavioral descriptions, so the xnfsyn +function works by matching statements that have some documented +structure, and substituting them for the equivalent XNF component. A +fully synthesize-able design, then, is one where the behavioral +statements can all be matched and substituted by the xnfsyn function. XNFIO FUNCTION @@ -50,6 +84,10 @@ IBUF, NOT gates cannot be absorbed as in the OPAD case. $Log: xnf.txt,v $ + Revision 1.2 1999/07/18 21:17:51 steve + Add support for CE input to XNF DFF, and do + complete cleanup of replaced design nodes. + Revision 1.1 1999/05/01 02:57:11 steve XNF target documentation. diff --git a/xnfsyn.cc b/xnfsyn.cc index 82a9007b5..1a7abb08f 100644 --- a/xnfsyn.cc +++ b/xnfsyn.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: xnfsyn.cc,v 1.1 1999/07/18 05:52:47 steve Exp $" +#ident "$Id: xnfsyn.cc,v 1.2 1999/07/18 21:17:51 steve Exp $" #endif /* @@ -29,7 +29,16 @@ * * Currently, this transform recognizes the following patterns: * - * always @(posedge CLK) Q = D // DFF + * always @(posedge CLK) Q = D // DFF:D,Q,C + * always @(negedge CLK) Q = D // DFF:D,Q,~C + * + * 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-bine identifiers. Enough + * devices will be created to accommodate the width of Q and D, though + * the CLK and CE will be shared by all the devices. */ # include "functor.h" # include "netlist.h" @@ -40,7 +49,21 @@ class xnfsyn_f : public functor_t { void process(class Design*, class NetProcTop*); private: - void proc_always(class Design*, class NetProcTop*); + 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_; }; @@ -52,68 +75,154 @@ void xnfsyn_f::process(class Design*des, class NetProcTop*top) { switch (top->type()) { case NetProcTop::KALWAYS: - proc_always(des, top); + top_ = top; + proc_always_(des); break; } - } /* - * Look for DFF devices. The pattern I'm looking for is: - * - * always @(posedge CLK) Q = D; - * - * This creates a DFF with the CLK, D and Q hooked up the obvious - * way. CE and PRE/CLR are left unconnected. + * An "always ..." statement has been found. */ -void xnfsyn_f::proc_always(class Design*des, class NetProcTop*top) +void xnfsyn_f::proc_always_(class Design*des) { // The statement must be a NetPEvent, ... - const NetProc*st = top->statement(); - const NetPEvent*ev = dynamic_cast(st); - if (ev == 0) + pclk_ = dynamic_cast(top_->statement()); + if (pclk_ == 0) return; // ... there must be a single event source, ... - svector*neb = ev->back_list(); + svector*neb = pclk_->back_list(); if (neb == 0) return; if (neb->count() != 1) { delete neb; return; } - const NetNEvent*nev = (*neb)[0]; + nclk_ = (*neb)[0]; delete neb; - // ... the event must be POSEDGE, ... - if (nev->type() != NetNEvent::POSEDGE) + // ... the event must be an edge, ... + switch (nclk_->type()) { + case NetNEvent::POSEDGE: + case NetNEvent::NEGEDGE: + break; + default: return; + } - // the NetPEvent must guard an assignment, ... - const NetAssign*asn = dynamic_cast(ev->statement()); - if (asn == 0) + // 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 xnfsyn_f::proc_casn_(class Design*des) +{ // ... and the rval must be a simple signal. - const NetESignal*sig = dynamic_cast(asn->rval()); + NetESignal*sig = dynamic_cast(asn_->rval()); if (sig == 0) return ; - // XXXX For now, only handle single bit. - assert(asn->pin_count() == 1); - assert(sig->pin_count() == 1); + // The signal and the assignment must be the same width... + assert(asn_->pin_count() == sig->pin_count()); - NetUDP*dff = new NetUDP(asn->name(), 3, true); - connect(dff->pin(0), asn->pin(0)); - connect(dff->pin(1), sig->pin(0)); - connect(dff->pin(2), nev->pin(0)); + // Geneate enough DFF objects to handle the entire width. + for (unsigned idx = 0 ; idx < asn_->pin_count() ; idx += 1) { - dff->attribute("XNF-LCA", "DFF:Q,D,CLK"); - des->add_node(dff); + // XXXX FIXME: Objects need unique names! + NetUDP*dff = new NetUDP(asn_->name(), 3, true); + + connect(dff->pin(0), asn_->pin(idx)); + connect(dff->pin(1), sig->pin(idx)); + connect(dff->pin(2), nclk_->pin(0)); + + switch (nclk_->type()) { + case NetNEvent::POSEDGE: + dff->attribute("XNF-LCA", "DFF:Q,D,C"); + break; + case NetNEvent::NEGEDGE: + dff->attribute("XNF-LCA", "DFF:Q,D,~C"); + break; + } + + des->add_node(dff); + } // This process is matched and replaced with a DFF. Get // rid of the now useless NetProcTop. - des->delete_process(top); + des->delete_process(top_); +} + +/* + * The process si far has been matches as: + * + * always @(posedge nclk_) if ...; + * always @(negedge nclk_) if ...; + */ +void xnfsyn_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; + + // Geneate enough DFF objects to handle the entire width. + for (unsigned idx = 0 ; idx < asn_->pin_count() ; idx += 1) { + + // XXXX FIXME: Objects need unique names! + NetUDP*dff = new NetUDP(asn_->name(), 4, true); + + connect(dff->pin(0), asn_->pin(idx)); + connect(dff->pin(1), sig->pin(idx)); + connect(dff->pin(2), nclk_->pin(0)); + connect(dff->pin(3), ce->pin(0)); + + switch (nclk_->type()) { + case NetNEvent::POSEDGE: + dff->attribute("XNF-LCA", "DFF:Q,D,C,CE"); + break; + case NetNEvent::NEGEDGE: + dff->attribute("XNF-LCA", "DFF:Q,D,~C,CE"); + break; + } + + des->add_node(dff); + } + + // This process is matched and replaced with a DFF. Get + // rid of the now useless NetProcTop. + des->delete_process(top_); } void xnfsyn(Design*des) @@ -124,6 +233,10 @@ void xnfsyn(Design*des) /* * $Log: xnfsyn.cc,v $ + * Revision 1.2 1999/07/18 21:17:51 steve + * Add support for CE input to XNF DFF, and do + * complete cleanup of replaced design nodes. + * * Revision 1.1 1999/07/18 05:52:47 steve * xnfsyn generates DFF objects for XNF output, and * properly rewrites the Design netlist in the process.