/* * Copyright (c) 1998-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) && !defined(macintosh) #ident "$Id: t-verilog.cc,v 1.12 2000/08/08 01:50:42 steve Exp $" #endif /* * This rather interesting target generates Verilog from the * design. This is interesting since by the time I get here, * elaboration and generic optimizations have been performed. This is * useful for feeding optimized designs to other tools, or the human * for debugging. */ # include # include # include # include # include "target.h" extern const struct target tgt_verilog; class target_verilog : public target_t { public: virtual void start_design(ostream&os, const Design*); virtual void signal(const NetNet*); virtual void logic(const NetLogic*); virtual void bufz(const NetBUFZ*); virtual bool process(const NetProcTop*); virtual bool proc_block(const NetBlock*); virtual bool proc_delay(const NetPDelay*); virtual void proc_stask(const NetSTask*); virtual void end_design(const Design*); private: void start_process(const NetProcTop*); void end_process(const NetProcTop*); unsigned indent_; ostream*out_; # define OS (*out_) void emit_expr_(ostream&os, const NetExpr*); }; /* * The output of the design starts here. The emit operation calls the * design_start and design_end target methods around the scan of the * design. Targets can use these hooks to generate header or footer * information if desired. */ void target_verilog::start_design(ostream&os, const Design*) { indent_ = 0; os << "module " << "main" << ";" << endl; out_ = &os; } /* * Emit first iterates over all the signals. This gives the target a * chance to declare signal variables before the network is assembled * or behaviors are written. */ void target_verilog::signal(const NetNet*net) { OS << " " << net->type(); if (net->pin_count() > 1) OS << " [" << net->msb() << ":" << net->lsb() << "]"; if (net->rise_time()) OS << " #" << net->rise_time(); OS << " " << mangle(net->name()) << ";" << endl; } void target_verilog::logic(const NetLogic*net) { switch (net->type()) { case NetLogic::AND: OS << " and"; break; case NetLogic::NAND: OS << " nand"; break; case NetLogic::NOR: OS << " nor"; break; case NetLogic::NOT: OS << " not"; break; case NetLogic::OR: OS << " or"; break; case NetLogic::XNOR: OS << " xnor"; break; case NetLogic::XOR: OS << " xor"; break; } OS << " #" << net->rise_time() << " " << mangle(net->name()) << "("; unsigned sidx; const NetNet*sig = find_link_signal(net, 0, sidx); OS << mangle(sig->name()) << "[" << sidx << "]"; for (unsigned idx = 1 ; idx < net->pin_count() ; idx += 1) { sig = find_link_signal(net, idx, sidx); assert(sig); OS << ", " << mangle(sig->name()) << "[" << sidx << "]"; } OS << ");" << endl; } void target_verilog::bufz(const NetBUFZ*net) { assert( net->pin_count() == 2 ); OS << " assign "; unsigned sidx; const NetNet*sig = find_link_signal(net, 0, sidx); OS << mangle(sig->name()) << "[" << sidx << "] = "; sig = find_link_signal(net, 1, sidx); OS << mangle(sig->name()) << "[" << sidx << "];" << endl; } bool target_verilog::process(const NetProcTop*top) { start_process(top); bool rc = top->statement()->emit_proc(this); end_process(top); return rc; } void target_verilog::start_process(const NetProcTop*proc) { switch (proc->type()) { case NetProcTop::KINITIAL: OS << " initial" << endl; break; case NetProcTop::KALWAYS: OS << " always" << endl; break; } indent_ = 6; } void target_verilog::end_process(const NetProcTop*) { } void target_verilog::emit_expr_(ostream&os, const NetExpr*expr) { if (const NetEConst*pp = dynamic_cast(expr)) { os << pp->value(); } else if (const NetEIdent*pp = dynamic_cast(expr)) { os << mangle(pp->name()); } else if (const NetEUnary*pp = dynamic_cast(expr)) { os << pp->op() << "("; emit_expr_(os, pp->expr()); os << ")"; } else { os << "(huh?)"; } } bool target_verilog::proc_block(const NetBlock*net) { OS << setw(indent_) << "" << "begin" << endl; indent_ += 4; net->emit_recurse(this); indent_ -= 4; OS << setw(indent_) << "" << "end" << endl; return true; } bool target_verilog::proc_delay(const NetPDelay*net) { OS << setw(indent_) << "" << "#" << net->delay() << endl; indent_ += 4; bool flag = net->emit_proc_recurse(this); indent_ -= 4; return flag; } static void vtask_parm(ostream&os, const NetExpr*ex) { if (const NetEConst*pp = dynamic_cast(ex)) { if (pp->value().is_string()) os << "\"" << pp->value().as_string() << "\""; else os << pp->value(); } else if (const NetEIdent*pp = dynamic_cast(ex)) { os << mangle(pp->name()); } else { } } void target_verilog::proc_stask(const NetSTask*net) { OS << setw(indent_) << "" << net->name(); if (net->nparms() > 0) { OS << "("; vtask_parm(OS, net->parm(0)); for (unsigned idx = 1 ; idx < net->nparms() ; idx += 1) { OS << ", "; vtask_parm(OS, net->parm(idx)); } OS << ")"; } OS << ";" << endl; } /* * All done with the design. Flush any output that I've been holding * off, and write the footers for the target. */ void target_verilog::end_design(const Design*) { OS << "endmodule" << endl; } static target_verilog tgt_verilog_obj; const struct target tgt_verilog = { "verilog", &tgt_verilog_obj }; /* * $Log: t-verilog.cc,v $ * Revision 1.12 2000/08/08 01:50:42 steve * target methods need not take a file stream. * * Revision 1.11 2000/07/29 16:21:08 steve * Report code generation errors through proc_delay. * * Revision 1.10 2000/04/12 04:23:58 steve * Named events really should be expressed with PEIdent * objects in the pform, * * Handle named events within the mix of net events * and edges. As a unified lot they get caught together. * wait statements are broken into more complex statements * that include a conditional. * * Do not generate NetPEvent or NetNEvent objects in * elaboration. NetEvent, NetEvWait and NetEvProbe * take over those functions in the netlist. * * Revision 1.9 2000/02/23 02:56:55 steve * Macintosh compilers do not support ident. * * Revision 1.8 1999/09/22 16:57:24 steve * Catch parallel blocks in vvm emit. * * Revision 1.7 1999/08/01 16:34:50 steve * Parse and elaborate rise/fall/decay times * for gates, and handle the rules for partial * lists of times. * * Revision 1.6 1999/07/03 02:12:52 steve * Elaborate user defined tasks. * * Revision 1.5 1999/06/13 16:30:06 steve * Unify the NetAssign constructors a bit. * * Revision 1.4 1999/05/01 02:57:53 steve * Handle much more complex event expressions. * * Revision 1.3 1998/12/01 00:42:15 steve * Elaborate UDP devices, * Support UDP type attributes, and * pass those attributes to nodes that * are instantiated by elaboration, * Put modules into a map instead of * a simple list. * * Revision 1.2 1998/11/23 00:20:23 steve * NetAssign handles lvalues as pin links * instead of a signal pointer, * Wire attributes added, * Ability to parse UDP descriptions added, * XNF generates EXT records for signals with * the PAD attribute. * * Revision 1.1 1998/11/03 23:29:05 steve * Introduce verilog to CVS. * */