degate  0.1.2
VerilogTBCodeTemplateGenerator.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 <VerilogTBCodeTemplateGenerator.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 VerilogTBCodeTemplateGenerator::VerilogTBCodeTemplateGenerator(std::string const& entity_name,
00032                                                                std::string const& description,
00033                                                                std::string const& logic_class) :
00034   VerilogCodeTemplateGenerator(entity_name, description, logic_class) {
00035 }
00036 
00037 VerilogTBCodeTemplateGenerator::~VerilogTBCodeTemplateGenerator() {
00038 }
00039 
00040 std::string VerilogTBCodeTemplateGenerator::generate() const {
00041 
00042   port_map_type port_map;
00043   BOOST_FOREACH(std::string const& port_name, get_inports()) 
00044     port_map[port_name] = port_name;
00045   BOOST_FOREACH(std::string const& port_name, get_outports())
00046     port_map[port_name] = port_name;
00047 
00048   return
00049     generate_header() +
00050     generate_module(entity_name);
00051                           
00052 }
00053 
00054 std::string VerilogTBCodeTemplateGenerator::generate_header() const {
00055   boost::format f("/**\n"
00056                   " * This is Verilog testbench for a gate of type %1%\n"
00057                   " *\n"
00058                   " *  Please customize this code template according to your needs.\n"
00059                   " */\n\n"
00060                   "`timescale 1ns/100ps\n"
00061                   "\n\n");
00062   f % entity_name;
00063   return f.str();
00064 }
00065 
00066 
00067 std::string VerilogTBCodeTemplateGenerator::generate_module(std::string const& device_type_name) const {
00068     
00069   std::string inports = 
00070     boost::algorithm::join(generate_identifier<std::vector<std::string> >(get_inports()), ", ");
00071   
00072   std::string outports = 
00073     boost::algorithm::join(generate_identifier<std::vector<std::string> >(get_outports()), ", ");
00074   
00075   std::list<std::string> port_wiring;
00076   BOOST_FOREACH(std::string const & pname, 
00077                 generate_identifier(get_ports())) {
00078     boost::format f(".%1%(%2%)");
00079     f % pname % pname;
00080     port_wiring.push_back(f.str());
00081   }
00082   
00083   std::string inport_init;
00084   BOOST_FOREACH(std::string const & pname, 
00085                 generate_identifier(get_inports())) {
00086       boost::format f("    %1% <= 1'b0;\n");
00087       f % pname;
00088       inport_init += f.str();
00089   }
00090   
00091   boost::format f("module testbench_%1%;\n"
00092                   "  reg %2%;\n"
00093                   "  wire %3%;\n"
00094                   "\n"
00095                   "  // helper task to simulate a C-style assert() function\n"
00096                   "  task assert;\n"
00097                   "    input asserted_value;\n"
00098                   "    begin\n"
00099                   "      if(!asserted_value) begin\n"
00100                   "        $display(\"Assertion failed.\");\n"
00101                   "        $finish;\n"
00102                   "      end\n"
00103                   "    end\n"
00104                   "  endtask\n"
00105                   "\n"
00106                   "  // create an instance of the device to test\n"
00107                   "  %4% unit(%5%);\n"
00108                   "\n"
00109                   "  // initialize\n"
00110                   "  initial begin\n"
00111                   "    // Enable signal dumping\n"
00112                   "    // Generate a VCD dump file. Please, do not change the filename.\n"
00113                   "    $dumpfile(\"test.vcd\"); \n"
00114                   "    $dumpvars(0, testbench_%6%); // for this module\n"
00115                   "\n"
00116                   "    // initialize signals on ports\n"
00117                   "%7%"
00118                   "  end\n"
00119                   "\n"
00120                   "  initial begin\n"
00121                   "    #10; // wait 10 ns for port initialisation\n"
00122                   "\n"
00123                   "%8%"
00124                   "\n"
00125                   "    #10; // wait 10 ns\n"
00126                   "\n"
00127                   "  end\n"
00128                   "\n"
00129                   "endmodule // testbench_%9%");
00130   f % generate_identifier(device_type_name, "dg_")
00131     % inports
00132     % outports
00133     % generate_identifier(device_type_name, "dg_") % boost::algorithm::join(port_wiring, ", ")
00134     % generate_identifier(device_type_name, "dg_")
00135     % inport_init
00136     
00137     % generate_all_assignments(get_inports(), get_outports())
00138     
00139     % generate_identifier(device_type_name, "dg_");
00140 
00141   return f.str();    
00142 }
00143 
00144 
00145 /**
00146  * Recursive implementation of an increment function.
00147  * Starts with MSB and increments until position right to LSB is reached.
00148  * @return Returns false, if there is nothing to do.
00149  */
00150 bool increment(std::vector<int> & assignment, size_t pos = 0) {
00151   if(assignment.size() == 0) return false;
00152 
00153   // toggle lsb
00154   if(assignment[pos] == 0) {
00155     assignment[pos] = 1;
00156     return true;
00157   }
00158   else {
00159     assignment[pos] = 0;
00160     if(pos + 1 == assignment.size()) return false;
00161     else return increment(assignment, pos + 1);
00162   }
00163       
00164 }
00165 
00166 std::string VerilogTBCodeTemplateGenerator::generate_all_assignments
00167 (std::vector<std::string> const& in_port_idents, 
00168  std::vector<std::string> const& out_port_idents) const {
00169 
00170   // left side: {a, b, c, ... }
00171   std::string assignment_dst = 
00172     "{" +
00173     boost::algorithm::join(generate_identifier<std::vector<std::string> >(in_port_idents), ", ") + 
00174     "}";
00175 
00176   // right side prefix
00177   boost::format f_prefix("%1%'b");
00178   f_prefix % in_port_idents.size();
00179   std::string prefix = f_prefix.str();
00180 
00181 
00182   std::string testcode;
00183 
00184   std::vector<int> assignment(in_port_idents.size()); // initialized with 0
00185   while(increment(assignment)) {
00186 
00187     std::string assignment2;
00188     BOOST_FOREACH(int i, assignment) 
00189       assignment2.push_back(boost::lexical_cast<char>(i));
00190     std::reverse(assignment2.begin(), assignment2.end());
00191 
00192     // generate assignemt string
00193     boost::format f("    %1% = %2%%3%;\n"
00194                     "    #10;\n");
00195     f % assignment_dst % prefix % assignment2;
00196 
00197     testcode += f.str();
00198     BOOST_FOREACH(std::string const& oport,
00199                   generate_identifier<std::vector<std::string> >(out_port_idents)) {
00200       boost::format f2("    assert(%1% === 1'bX); // please edit\n\n");
00201       f2 % oport;
00202       testcode += f2.str();
00203     }
00204 
00205   }
00206 
00207   return testcode;
00208 }
00209