degate  0.1.2
VerilogCodeTemplateGenerator.cc
Go to the documentation of this file.
00001 /* -*-c++-*-
00002 
00003  This file is part of the IC reverse engineering tool degate.
00004 
00005  Copyright 2008, 2009, 2010 by Martin Schobert
00006 
00007  Degate is free software: you can redistribute it and/or modify
00008  it under the terms of the GNU General Public License as published by
00009  the Free Software Foundation, either version 3 of the License, or
00010  any later version.
00011 
00012  Degate is distributed in the hope that it will be useful,
00013  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  GNU General Public License for more details.
00016 
00017  You should have received a copy of the GNU General Public License
00018  along with degate. If not, see <http://www.gnu.org/licenses/>.
00019 
00020 */
00021 
00022 
00023 #include <VerilogCodeTemplateGenerator.h>
00024 #include <boost/format.hpp>
00025 #include <boost/foreach.hpp>
00026 #include <boost/algorithm/string/join.hpp>
00027 
00028 using namespace boost;
00029 using namespace degate;
00030 
00031 VerilogCodeTemplateGenerator::VerilogCodeTemplateGenerator(std::string const& entity_name,
00032                                                            std::string const& description,
00033                                                            std::string const& logic_class) :
00034   CodeTemplateGenerator(entity_name, description, logic_class) {
00035 }
00036 
00037 
00038 VerilogCodeTemplateGenerator::~VerilogCodeTemplateGenerator() {
00039 }
00040 
00041 std::string VerilogCodeTemplateGenerator::generate() const {
00042   return
00043     generate_common() + 
00044     generate_header() +
00045     generate_module(entity_name, generate_port_list()) +
00046     generate_port_definition() +
00047     generate_impl(logic_class) + 
00048     "\n\n"
00049     "endmodule\n\n";
00050 }
00051 
00052 std::string VerilogCodeTemplateGenerator::generate_common() const {
00053   return "";
00054 }
00055 
00056 std::string VerilogCodeTemplateGenerator::generate_header() const {
00057   boost::format f("/** \n"
00058                   " * This is a Verilog implementation for a gate of type %1%.\n"
00059                   " */\n\n"
00060                   "// Please customize this code template according to your needs.\n"
00061                   "\n\n");
00062   f % entity_name;
00063   return f.str();
00064 }
00065 
00066 std::string VerilogCodeTemplateGenerator::generate_module(std::string const& entity_name,
00067                                                           std::string const& port_description) const {
00068 
00069   boost::format f("module %1% (\n"
00070                   "%2%"
00071                   ");\n\n");
00072   f % generate_identifier(entity_name, "dg_")
00073     % port_description;
00074   return f.str();
00075 }
00076 
00077 std::string VerilogCodeTemplateGenerator::generate_port_list() const {
00078 
00079   boost::format f("  %1%%2%\n"
00080                   "  %3%\n");
00081   f % boost::algorithm::join(generate_identifier<std::vector<std::string> >(get_inports()), ", ")
00082     % (get_inports().size() > 0 ? ", " : "")
00083     % boost::algorithm::join(generate_identifier<std::vector<std::string> >(get_outports()), ", ");
00084   return f.str();
00085 }
00086 
00087 
00088 std::string VerilogCodeTemplateGenerator::generate_port_definition() const {
00089   std::string ret;
00090 
00091   ret += "  // input ports\n";
00092   BOOST_FOREACH(std::string const& port_name, 
00093                 generate_identifier<std::vector<std::string> >(get_inports())) {
00094     boost::format f("  input %1%;\n");
00095     f % port_name;    
00096     ret += f.str();
00097   }
00098 
00099 
00100   ret += "\n  // output ports\n";
00101   BOOST_FOREACH(std::string const& port_name, 
00102                 generate_identifier<std::vector<std::string> >(get_outports())) {
00103     boost::format f("  output %1%;\n");
00104     f % port_name;    
00105     ret += f.str();
00106   }
00107 
00108   ret += "\n";
00109 
00110   return ret;
00111 }
00112 
00113 
00114 std::string VerilogCodeTemplateGenerator::generate_impl(std::string const& logic_class) const {
00115 
00116   std::vector<std::string> in = get_inports();
00117   std::vector<std::string> out = get_outports();
00118 
00119   if(in.size() == 0 || out.size() == 0) 
00120     throw DegateRuntimeException("The standard cell has either no input port or no ouput port.");
00121 
00122   std::string clock_name = get_port_name_by_type(CLOCK);
00123   if(clock_name.empty()) clock_name = "clock";
00124   std::string reset_name = get_port_name_by_type(RESET);
00125   if(reset_name.empty()) reset_name = "reset";
00126   std::string enable_name = get_port_name_by_type(ENABLE);
00127   if(reset_name.empty()) reset_name = "enable";
00128 
00129   if(logic_class == "inverter" &&
00130      in.size() == 1 && out.size() == 1) {
00131 
00132     boost::format f("  assign %1% = ~%2%;");
00133     f % generate_identifier(out[0]) % generate_identifier(in[0]);
00134     return f.str();
00135   }
00136   else if(logic_class == "tristate-inverter" ||
00137           logic_class == "tristate-inverter-lo-actiSve" ||
00138           logic_class == "tristate-inverter-hi-active") {
00139 
00140     bool low_active = logic_class == "tristate-inverter-lo-active";
00141 
00142     boost::format f("  tri %1%; // ???\n\n"
00143                     "  assign %2% = %3%%4% ? ~%5% : 1'bz;");
00144     f % generate_identifier(out[0]) 
00145       % generate_identifier(out[0])
00146       % (low_active ? "~" : "")
00147       % generate_identifier(enable_name)
00148       % generate_identifier(get_first_port_name_not_in(in, enable_name));
00149     return f.str();
00150   }
00151   else if((logic_class == "xor" ||
00152            logic_class == "or" ||
00153            logic_class == "and" ||
00154            logic_class == "nor" ||
00155            logic_class == "nand" ||
00156            logic_class == "xnor") &&
00157           in.size() >= 2 && out.size() == 1) {
00158 
00159     std::string inner_op, outer_op = "~";
00160 
00161     if(logic_class == "nand") inner_op = "&";
00162     else if(logic_class == "nor") inner_op = "|";
00163     else if(logic_class == "xnor") inner_op = "^";
00164     else {
00165       outer_op = "";
00166       if(logic_class == "and") inner_op = "&";
00167       else if(logic_class == "or") inner_op = "|";
00168       else if(logic_class == "xor") inner_op = "^";
00169     }
00170 
00171     boost::format f("  assign %1% = %2%%3%%4%%5%;"); 
00172     f % generate_identifier(out[0])
00173       % outer_op
00174       % (outer_op.empty() ? "" : "(")
00175       % boost::algorithm::join(generate_identifier<std::vector<std::string> >(in),
00176                                std::string(" ") + inner_op + std::string(" "))
00177       % (outer_op.empty() ? "" : ")");
00178 
00179     return f.str();
00180   }
00181   else if(logic_class == "buffer" && in.size() > 0 && out.size() > 0) {
00182     boost::format f("  assign %1% = %2%; // ???");
00183     f % generate_identifier(out[0]) % generate_identifier(in[0]);
00184     return f.str();
00185 
00186   }
00187   else if(logic_class == "buffer-tristate-hi-active" ||
00188           logic_class == "buffer-tristate-lo-active") {
00189     boost::format f("  tri %1%; // ???\n\n"
00190                     "  bufif%2%(%3%, %4%, %45);");
00191     f % generate_identifier(out[0])
00192       % (logic_class == "buffer-tristate-lo-active" ? "0" : "1")
00193       % generate_identifier(out[0])
00194       % generate_identifier(get_first_port_name_not_in(in, enable_name))
00195       % generate_identifier(enable_name);
00196     return f.str();
00197   }
00198   else if(logic_class == "latch-generic" ||
00199           logic_class == "latch-async-enable") {
00200     boost::format f("  reg %1%;\n\n"
00201                     "  always @(*)\n"
00202                     "    if (%2%) %3% = %4%;\n");
00203     f % generate_identifier(out[0])
00204       % generate_identifier(enable_name)
00205       % generate_identifier(out[0])
00206       % generate_identifier(get_first_port_name_not_in(in, enable_name));
00207     return f.str();
00208 
00209   }
00210   else if(logic_class == "latch-sync-enable") {
00211     return "  // stub not implemented, yet";
00212   }
00213   else if(logic_class == "flipflop") {
00214     boost::format f("  reg %1%;\n"
00215                     "\n"
00216                     "  always @(posedge %2%)\n"
00217                     "    %3% <= %4%;\n");
00218     f % generate_identifier(get_port_name_by_type(Q))
00219       % generate_identifier(get_port_name_by_type(CLOCK))
00220       % generate_identifier(get_port_name_by_type(Q))
00221       % generate_identifier(get_port_name_by_type(D));
00222 
00223     if(get_port_name_by_type(NOT_Q).empty())
00224       return f.str();
00225     else {
00226       boost::format f2("\n"
00227                        "  reg %1%;\n"
00228                        "\n"
00229                        "  always @*\n"
00230                        "    %2% <= ~%3%;\n");
00231       f2 % generate_identifier(get_port_name_by_type(NOT_Q))
00232         % generate_identifier(get_port_name_by_type(NOT_Q))
00233         % generate_identifier(get_port_name_by_type(Q));
00234 
00235         return f.str() + f2.str();
00236     }
00237   }
00238   else if(logic_class == "flipflop-sync-rst") {
00239     boost::format f("  reg %1%;\n"
00240                     "\n"
00241                     "  always @(posedge %2%)\n"
00242                     "    if(%3%) // synchronous reset\n"
00243                     "      %4% <= 1'b0;\n"
00244                     "    else\n"
00245                     "      %5% <= %6%;\n");
00246     f % generate_identifier(get_port_name_by_type(Q)) // reg
00247       % generate_identifier(get_port_name_by_type(CLOCK)) // always
00248 
00249       % generate_identifier(get_port_name_by_type(RESET)) // if
00250 
00251       % generate_identifier(get_port_name_by_type(Q))
00252       % generate_identifier(get_port_name_by_type(Q))
00253       % generate_identifier(get_port_name_by_type(D));
00254 
00255 
00256     if(get_port_name_by_type(NOT_Q).empty())
00257       return f.str();
00258     else {
00259       boost::format f2("\n"
00260                        "  reg %1%;\n"
00261                        "\n"
00262                        "  always @*\n"
00263                        "    %2% <= ~%3%;\n");
00264       f2 % generate_identifier(get_port_name_by_type(NOT_Q))
00265         % generate_identifier(get_port_name_by_type(NOT_Q))
00266         % generate_identifier(get_port_name_by_type(Q));
00267 
00268         return f.str() + f2.str();
00269     }
00270     
00271   }
00272   else if(logic_class == "flipflop-async-rst") {
00273     boost::format f("  reg %1%;\n"
00274                     "\n"
00275                     "  always @(posedge %2% or posedge %3%)\n"
00276                     "    if(%4%) // asynchronous reset\n"
00277                     "      %5% <= 1'b0;\n"
00278                     "    else\n"
00279                     "      %6% <= %7%;\n");
00280     f % generate_identifier(get_port_name_by_type(Q)) // reg
00281       % generate_identifier(get_port_name_by_type(CLOCK)) // always
00282       % generate_identifier(get_port_name_by_type(RESET)) // always
00283 
00284       % generate_identifier(get_port_name_by_type(RESET)) // if
00285 
00286       % generate_identifier(get_port_name_by_type(Q))
00287       % generate_identifier(get_port_name_by_type(Q))
00288       % generate_identifier(get_port_name_by_type(D));
00289 
00290     if(get_port_name_by_type(NOT_Q).empty())
00291       return f.str();
00292     else {
00293       boost::format f2("\n"
00294                        "  reg %1%;\n"
00295                        "\n"
00296                        "  always @*\n"
00297                        "    %2% <= ~%3%;\n");
00298       f2 % generate_identifier(get_port_name_by_type(NOT_Q))
00299         % generate_identifier(get_port_name_by_type(NOT_Q))
00300         % generate_identifier(get_port_name_by_type(Q));
00301 
00302         return f.str() + f2.str();
00303     }
00304 
00305   }
00306   else if(logic_class == "generic-combinational-logic" ||
00307           logic_class == "ao" ||
00308           logic_class == "aoi" ||
00309           logic_class == "oa" ||
00310           logic_class == "oai") {
00311     
00312     std::string ret;
00313     BOOST_FOREACH(std::string const& oport,
00314                   generate_identifier<std::vector<std::string> >(get_outports())) {
00315       boost::format f("  assign %1% = ...;\n");
00316       f % oport;
00317       ret += f.str();
00318     }
00319                   
00320     return ret;
00321   }
00322   else if(logic_class == "half-adder") {
00323     return "  // assign {cout,sum} = a + b + cin;\n";
00324   }
00325   else if(logic_class == "full-adder") {
00326     return "  // stub not implemented, yet";
00327   }
00328   else if(logic_class == "mux") {
00329 
00330     boost::format f("  reg %1%;\n"
00331                     "\n"
00332                     "  always @*\n"
00333                     "    begin\n"
00334                     "      %2% = 1'b0; // default\n"
00335                     "      case({sel1, sel0}) // just an example\n"
00336                     "        2'b00 : %3% = a;\n"
00337                     "        2'b01 : %4% = b;\n"
00338                     "        2'b10 : %5% = c;\n"
00339                     "        2'b11 : %6% = d;\n"
00340                     "      endcase\n"
00341                     "    end\n");
00342     f % generate_identifier(out[0]) 
00343       % generate_identifier(out[0]) 
00344       % generate_identifier(out[0]) 
00345       % generate_identifier(out[0]) 
00346       % generate_identifier(out[0]) 
00347       % generate_identifier(out[0]);
00348     return f.str();
00349   }
00350   else if(logic_class == "demux") {
00351     boost::format f("  reg a, b, c, d;\n"
00352                     "\n"
00353                     "  always @*\n"
00354                     "    begin\n"
00355                     "      %1% = 1'b0; // default\n"
00356                     "      case({sel1, sel0}) // just an example\n"
00357                     "        2'b00 : a = %2%;\n"
00358                     "        2'b01 : b = %3%;\n"
00359                     "        2'b10 : c = %4%;\n"
00360                     "        2'b11 : d = %5%;\n"
00361                     "      endcase\n"
00362                     "    end\n");
00363     f % generate_identifier(in[0]) 
00364       % generate_identifier(in[0]) 
00365       % generate_identifier(in[0]) 
00366       % generate_identifier(in[0]) 
00367       % generate_identifier(in[0]);
00368     return f.str();
00369   }
00370 
00371   return
00372     "/*\n"
00373     " * Please implement behaviour.\n"
00374     " */\n";
00375 }
00376 
00377 
00378 std::string VerilogCodeTemplateGenerator::generate_identifier(std::string const& name, 
00379                                                               std::string const& prefix) const {
00380   std::string identifier = prefix;
00381 
00382   bool first_char = prefix == "" ? true : false;
00383   BOOST_FOREACH(char c, name) {
00384     if(c == '/' || c == '!' || c == '~') identifier.append("not");
00385     else if(first_char && !isalpha(c)) {
00386       identifier.push_back('_');
00387       identifier.push_back(c);
00388     }
00389     else if(isalnum(c)) identifier.push_back(c);
00390     else identifier.push_back('_');
00391 
00392     first_char = false;
00393   }
00394   return identifier;
00395 }
00396 
00397