|
degate 0.1.1
|
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
1.7.4