|
degate 0.1.1
|
00001 /* 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 #include <ProjectImporter.h> 00023 #include <Layer.h> 00024 #include <FileSystem.h> 00025 #include <degate_exceptions.h> 00026 #include <GateLibraryImporter.h> 00027 #include <LogicModelImporter.h> 00028 #include <RCVBlacklistImporter.h> 00029 #include <PortColorManager.h> 00030 #include <Image.h> 00031 #include <LogicModelHelper.h> 00032 #include <ImageHelper.h> 00033 00034 #include <sys/types.h> 00035 #include <sys/stat.h> 00036 #include <unistd.h> 00037 #include <errno.h> 00038 00039 #include <string> 00040 #include <iostream> 00041 #include <sstream> 00042 #include <stdexcept> 00043 #include <list> 00044 00045 #include <boost/format.hpp> 00046 00047 using namespace std; 00048 using namespace degate; 00049 00050 std::string ProjectImporter::get_project_filename(std::string const& dir) const { 00051 00052 if(is_directory(dir)) 00053 return join_pathes(dir, "project.xml"); 00054 else 00055 return dir; 00056 } 00057 00058 Project_shptr ProjectImporter::import_all(std::string const& directory) { 00059 Project_shptr prj = import(directory); 00060 00061 if(prj != NULL) { 00062 00063 GateLibraryImporter gl_importer; 00064 00065 GateLibrary_shptr gate_lib; 00066 00067 std::string gate_lib_file(get_basedir(directory) + "/gate_library.xml"); 00068 std::string rcbl_file(get_basedir(directory) + "/rc_blacklist.xml"); 00069 00070 if(file_exists(gate_lib_file)) 00071 gate_lib = gl_importer.import(gate_lib_file); 00072 else gate_lib = GateLibrary_shptr(new GateLibrary()); 00073 00074 LogicModelImporter lm_importer(prj->get_width(), prj->get_height(), gate_lib); 00075 00076 lm_importer.import_into(prj->get_logic_model(), 00077 get_basedir(directory) + "/lmodel.xml"); 00078 00079 LogicModel_shptr lmodel = prj->get_logic_model(); 00080 lmodel->set_default_gate_port_diameter(prj->get_default_port_diameter()); 00081 00082 if(file_exists(rcbl_file)) { 00083 RCVBlacklistImporter rcvbl_importer(lmodel); 00084 rcvbl_importer.import_into(rcbl_file, prj->get_rcv_blacklist()); 00085 } 00086 00087 /* 00088 For degate projects that were exported with degate 0.0.6 the gate templates 00089 were expressed in terms of an image region. This is bad. Here is a part of the fix: 00090 We have loaded the project with the background images and we have the gate 00091 library. We iterate over the gate library, extract the template image from the 00092 background image and put it into the gate library. We do it for the first 00093 transistor, the first logic and the first metal layer. 00094 */ 00095 00096 debug(TM, "Check if we have template images."); 00097 for(GateLibrary::template_iterator iter = gate_lib->begin(); 00098 iter != gate_lib->end(); ++iter) { 00099 00100 debug(TM, "Will grab template image for gate template ID: %d", iter->first); 00101 GateTemplate_shptr tmpl = iter->second; 00102 assert(tmpl != NULL); 00103 00104 BoundingBox const& bbox = tmpl->get_bounding_box(); 00105 if(bbox.get_min_x() != 0 && bbox.get_min_y() != 0 && 00106 bbox.get_max_x() != 0 && bbox.get_max_y() != 0) { // a heuristic 00107 debug(TM, "Grab template images from the background for template %s.", tmpl->get_name().c_str()); 00108 grab_template_images(lmodel, tmpl, bbox); 00109 } 00110 00111 } 00112 debug(TM, "Project loaded."); 00113 //prj->print_all(cout); 00114 00115 } 00116 00117 return prj; 00118 } 00119 00120 Project_shptr ProjectImporter::import(std::string const& directory) { 00121 00122 string filename = get_project_filename(directory); 00123 if(RET_IS_NOT_OK(check_file(filename))) { 00124 debug(TM, "Problem: file %s not found.", filename.c_str()); 00125 throw InvalidPathException("The ProjectImporter cannot load the project file. File does not exists."); 00126 } 00127 00128 try { 00129 00130 xmlpp::DomParser parser; 00131 parser.set_substitute_entities(); // We just want the text to be resolved/unescaped automatically. 00132 00133 parser.parse_file(filename); 00134 assert(parser == true); 00135 00136 const xmlpp::Document * doc = parser.get_document(); 00137 assert(doc != NULL); 00138 00139 const xmlpp::Element * root_elem = doc->get_root_node(); // deleted by DomParser 00140 assert(root_elem != NULL); 00141 00142 // parse width and height 00143 int w = parse_number<length_t>(root_elem, "width"); 00144 int h = parse_number<length_t>(root_elem, "height"); 00145 00146 Project_shptr prj(new Project(w, h, get_basedir(filename))); 00147 assert(prj->get_project_directory().length() != 0); 00148 00149 parse_project_element(prj, root_elem); 00150 00151 return prj; 00152 } 00153 catch(const std::exception& ex) { 00154 std::cout << "Exception caught: " << ex.what() << std::endl; 00155 throw InvalidXMLException(ex.what()); 00156 } 00157 } 00158 00159 00160 void ProjectImporter::parse_layers_element(const xmlpp::Element * const layers_elem, Project_shptr prj) { 00161 debug(TM, "parsing layers"); 00162 00163 const xmlpp::Node::NodeList layer_list = layers_elem->get_children("layer"); 00164 for(xmlpp::Node::NodeList::const_iterator iter = layer_list.begin(); 00165 iter != layer_list.end(); 00166 ++iter) { 00167 00168 if(const xmlpp::Element* layer_elem = dynamic_cast<const xmlpp::Element*>(*iter)) { 00169 00170 const std::string image_filename(layer_elem->get_attribute_value("image-filename")); 00171 const std::string layer_type_str(layer_elem->get_attribute_value("type")); 00172 const std::string layer_description(layer_elem->get_attribute_value("description")); 00173 unsigned int position = parse_number<unsigned int>(layer_elem, "position"); 00174 const std::string layer_enabled_str = layer_elem->get_attribute_value("enabled"); 00175 00176 Layer::LAYER_TYPE layer_type = Layer::get_layer_type_from_string(layer_type_str); 00177 layer_id_t layer_id = parse_number<layer_id_t>(layer_elem, "id", 0); 00178 00179 Layer_shptr new_layer(new Layer(prj->get_bounding_box(), layer_type)); 00180 LogicModel_shptr lmodel = prj->get_logic_model(); 00181 00182 debug(TM, "Parsed a layer entry for type %s. This is a %s layer. Background image is %s", 00183 layer_type_str.c_str(), 00184 Layer::get_layer_type_as_string(layer_type).c_str(), 00185 image_filename.c_str()); 00186 00187 bool layer_enabled = true; 00188 if(layer_enabled_str.size() != 0) 00189 layer_enabled = parse_bool(layer_enabled_str); 00190 new_layer->set_enabled(layer_enabled); 00191 00192 new_layer->set_description(layer_description); 00193 new_layer->set_layer_id(layer_id); 00194 00195 lmodel->add_layer(position, new_layer); 00196 00197 load_background_image(new_layer, image_filename, prj); 00198 00199 } 00200 } 00201 } 00202 00203 void ProjectImporter::load_background_image(Layer_shptr layer, 00204 std::string const& image_filename, 00205 Project_shptr prj) { 00206 00207 debug(TM, "try to load image [%s]", image_filename.c_str()); 00208 if(!image_filename.empty()) { 00209 00210 assert(prj->get_project_directory().length() != 0); 00211 00212 std::string image_path_to_load = join_pathes(prj->get_project_directory(), image_filename); 00213 00214 debug(TM, "try to load image [%s]", image_path_to_load.c_str()); 00215 00216 if(is_directory(image_path_to_load)) { // new background image format 00217 00218 debug(TM, "project importer loads an tile based image from [%s]", image_path_to_load.c_str()); 00219 00220 BackgroundImage_shptr bg_image = 00221 load_degate_image<BackgroundImage>(prj->get_width(), 00222 prj->get_height(), 00223 image_path_to_load); 00224 00225 if(bg_image == NULL) 00226 throw DegateRuntimeException("Failed to load the background image"); 00227 00228 debug(TM, "Loading done."); 00229 layer->set_image(bg_image); 00230 } 00231 else if(is_file(image_path_to_load)) { // old image background format 00232 00233 // determine where we can store the new backgound image 00234 boost::format fmter("layer_%1%.dimg"); 00235 /* We convert old degate background images to the new tile based format. 00236 Therefore we need directory names. The directory name should not reflect 00237 a layer position number, because it it possible that the layers become 00238 reorderd later. We do not want to rename the directories in that case. 00239 To avoid, that a user thinks the directory name reflects a layer position, 00240 we just add a number. */ 00241 fmter % (layer->get_layer_pos() + 0x2342); 00242 std::string new_dir(join_pathes(prj->get_project_directory(), fmter.str())); 00243 00244 debug(TM, "project importer loads an old single file based image from [%s]", 00245 image_path_to_load.c_str()); 00246 00247 if(!file_exists(new_dir) && !is_directory(new_dir)) { // we have to check this, before we call the constructor 00248 00249 // create new background image 00250 BackgroundImage_shptr new_bg_image(new BackgroundImage(prj->get_width(), 00251 prj->get_height(), 00252 new_dir)); 00253 00254 // load old single file image 00255 PersistentImage_RGBA_shptr old_bg_image = 00256 load_degate_image<PersistentImage_RGBA>(prj->get_width(), 00257 prj->get_height(), 00258 image_path_to_load); 00259 00260 if(new_bg_image == NULL) 00261 throw DegateRuntimeException("Failed to load the background image"); 00262 00263 // convert image into new format 00264 00265 debug(TM, "Copy the image into a new format. The data is stored in directory %s", 00266 new_dir.c_str()); 00267 00268 copy_image(new_bg_image, old_bg_image); 00269 00270 layer->set_image(new_bg_image); 00271 00272 } 00273 else { 00274 00275 debug(TM, 00276 "There is already a directory named %s. It should be loaded as an image now.", 00277 new_dir.c_str()); 00278 00279 BackgroundImage_shptr new_bg_image(new BackgroundImage(prj->get_width(), 00280 prj->get_height(), 00281 new_dir)); 00282 00283 layer->set_image(new_bg_image); 00284 } 00285 00286 00287 } 00288 00289 } 00290 else { 00291 debug(TM, "project in %s has no layer image defined for a layer.", 00292 prj->get_project_directory().c_str()); 00293 } 00294 } 00295 00296 00297 void ProjectImporter::parse_port_colors_element(const xmlpp::Element * const port_colors_elem, Project_shptr prj) { 00298 00299 const xmlpp::Node::NodeList color_list = port_colors_elem->get_children("port-color"); 00300 00301 PortColorManager_shptr port_color_manager = prj->get_port_color_manager(); 00302 00303 for(xmlpp::Node::NodeList::const_iterator iter = color_list.begin(); 00304 iter != color_list.end(); 00305 ++iter) { 00306 00307 if(const xmlpp::Element* color_elem = dynamic_cast<const xmlpp::Element*>(*iter)) { 00308 00309 const std::string port_name(color_elem->get_attribute_value("port-name")); 00310 const std::string fill_color_str(color_elem->get_attribute_value("fill-color")); 00311 const std::string frame_color_str(color_elem->get_attribute_value("frame-color")); 00312 00313 port_color_manager->set_color(port_name, 00314 parse_color_string(frame_color_str), 00315 parse_color_string(fill_color_str) ); 00316 00317 00318 } 00319 } 00320 00321 } 00322 00323 void ProjectImporter::parse_colors_element(const xmlpp::Element * const port_colors_elem, 00324 Project_shptr prj) { 00325 00326 const xmlpp::Node::NodeList color_list = port_colors_elem->get_children("color"); 00327 00328 for(xmlpp::Node::NodeList::const_iterator iter = color_list.begin(); 00329 iter != color_list.end(); 00330 ++iter) { 00331 00332 if(const xmlpp::Element* color_elem = dynamic_cast<const xmlpp::Element*>(*iter)) { 00333 00334 const std::string object_name(color_elem->get_attribute_value("object")); 00335 const std::string color_str(color_elem->get_attribute_value("color")); 00336 ENTITY_COLOR o; 00337 00338 if(!object_name.compare("wire")) o = DEFAULT_COLOR_WIRE; 00339 else if(!object_name.compare("via-up")) o = DEFAULT_COLOR_VIA_UP; 00340 else if(!object_name.compare("via-down")) o = DEFAULT_COLOR_VIA_DOWN; 00341 else if(!object_name.compare("grid")) o = DEFAULT_COLOR_GRID; 00342 else if(!object_name.compare("annotation")) o = DEFAULT_COLOR_ANNOTATION; 00343 else if(!object_name.compare("annotation-frame")) o = DEFAULT_COLOR_ANNOTATION_FRAME; 00344 else if(!object_name.compare("gate")) o = DEFAULT_COLOR_GATE; 00345 else if(!object_name.compare("gate-frame")) o = DEFAULT_COLOR_GATE_FRAME; 00346 else if(!object_name.compare("gate-port")) o = DEFAULT_COLOR_GATE_PORT; 00347 else if(!object_name.compare("text")) o = DEFAULT_COLOR_TEXT; 00348 else if(!object_name.compare("emarker")) o = DEFAULT_COLOR_EMARKER; 00349 else { 00350 boost::format f("Can't parse object type. '%1%'"); 00351 f % object_name; 00352 throw XMLAttributeParseException(f.str()); 00353 } 00354 prj->set_default_color(o, parse_color_string(color_str)); 00355 00356 } 00357 } 00358 00359 } 00360 00361 void ProjectImporter::parse_grids_element(const xmlpp::Element * const grids_elem, Project_shptr prj) { 00362 00363 xmlpp::Node::NodeList::const_iterator iter; 00364 00365 const xmlpp::Node::NodeList regular_grid_list = grids_elem->get_children("regular-grid"); 00366 const xmlpp::Node::NodeList irregular_grid_list = grids_elem->get_children("irregular-grid"); 00367 00368 00369 for(iter = regular_grid_list.begin(); iter != regular_grid_list.end(); ++iter) { 00370 if(const xmlpp::Element* regular_grid_elem = dynamic_cast<const xmlpp::Element*>(*iter)) { 00371 00372 const Glib::ustring orientation(regular_grid_elem->get_attribute_value("orientation")); 00373 00374 RegularGrid_shptr reg_grid = (orientation == "horizontal") ? 00375 prj->get_regular_horizontal_grid() : prj->get_regular_vertical_grid(); 00376 00377 reg_grid->set_distance(parse_number<unsigned int>(regular_grid_elem, "distance", 0)); 00378 reg_grid->set_enabled(parse_bool(regular_grid_elem->get_attribute_value("enabled"))); 00379 } 00380 } 00381 00382 for(iter = irregular_grid_list.begin(); iter != irregular_grid_list.end(); ++iter) { 00383 if(const xmlpp::Element* irregular_grid_elem = dynamic_cast<const xmlpp::Element*>(*iter)) { 00384 00385 const Glib::ustring orientation(irregular_grid_elem->get_attribute_value("orientation")); 00386 00387 IrregularGrid_shptr irreg_grid = (orientation == "horizontal") ? 00388 prj->get_irregular_horizontal_grid() : prj->get_irregular_vertical_grid(); 00389 00390 irreg_grid->set_enabled(parse_bool(irregular_grid_elem->get_attribute_value("enabled"))); 00391 00392 const xmlpp::Node::NodeList offsets_entry_list = irregular_grid_elem->get_children("offsets"); 00393 const xmlpp::Node::NodeList::const_iterator offsets_iter = offsets_entry_list.begin(); 00394 if(offsets_iter != offsets_entry_list.end()) { 00395 const xmlpp::Element* offsets_elem = dynamic_cast<const xmlpp::Element*>(*offsets_iter); 00396 if(offsets_elem != NULL) { 00397 00398 const xmlpp::Node::NodeList offset_entry_list = offsets_elem->get_children("offset-entry"); 00399 for(xmlpp::Node::NodeList::const_iterator offs_iter = offset_entry_list.begin(); 00400 offs_iter != offset_entry_list.end(); 00401 ++offs_iter) { 00402 if(const xmlpp::Element* offset_entry_elem = dynamic_cast<const xmlpp::Element*>(*offs_iter)) { 00403 irreg_grid->add_offset(parse_number<int>(offset_entry_elem, "offset")); 00404 } 00405 } 00406 } 00407 } 00408 } 00409 } 00410 } 00411 00412 00413 00414 void ProjectImporter::parse_project_element(Project_shptr parent_prj, 00415 const xmlpp::Element * const project_elem) { 00416 00417 int w = parent_prj->get_width(); 00418 int h = parent_prj->get_height(); 00419 00420 // Use geometry information to set up regular grid ranges. 00421 // The RegularGrid implementation might be changed in order to avoid this setup. 00422 RegularGrid_shptr reg_vert_grid = parent_prj->get_regular_vertical_grid(); 00423 RegularGrid_shptr reg_hor_grid = parent_prj->get_regular_horizontal_grid(); 00424 reg_vert_grid->set_range(0, w); 00425 reg_hor_grid->set_range(0, h); 00426 00427 parent_prj->set_degate_version(project_elem->get_attribute_value("degate-version")); 00428 parent_prj->set_name(project_elem->get_attribute_value("name")); 00429 parent_prj->set_description(project_elem->get_attribute_value("description")); 00430 00431 if(!project_elem->get_attribute_value("server-url").empty()) 00432 parent_prj->set_server_url(project_elem->get_attribute_value("server-url")); 00433 00434 if(!project_elem->get_attribute_value("last-pulled-transaction-id").empty()) 00435 parent_prj->set_last_pulled_tid(parse_number<transaction_id_t>(project_elem, 00436 "last-pulled-transaction-id")); 00437 00438 parent_prj->set_lambda(parse_number<length_t>(project_elem, "lambda")); 00439 parent_prj->set_default_pin_diameter(parse_number<diameter_t>(project_elem, "pin-diameter")); 00440 parent_prj->set_default_wire_diameter(parse_number<diameter_t>(project_elem, "wire-diameter")); 00441 parent_prj->set_default_port_diameter(parse_number<diameter_t>(project_elem, "port-diameter", 5)); 00442 00443 parent_prj->set_pixel_per_um(parse_number<double>(project_elem, "pixel-per-um", 0)); 00444 parent_prj->set_template_dimension(parse_number<int>(project_elem, "template-dimension", 0)); 00445 parent_prj->set_font_size(parse_number<unsigned int>(project_elem, "font-size", 10)); 00446 00447 const xmlpp::Element * e = get_dom_twig(project_elem, "grids"); 00448 if(e != NULL) parse_grids_element(e, parent_prj); 00449 00450 e = get_dom_twig(project_elem, "layers"); 00451 if(e != NULL) parse_layers_element(e, parent_prj); 00452 00453 e = get_dom_twig(project_elem, "port-colors"); 00454 if(e != NULL) parse_port_colors_element(e, parent_prj); 00455 00456 e = get_dom_twig(project_elem, "default-colors"); 00457 if(e != NULL) parse_colors_element(e, parent_prj); 00458 00459 }
1.7.4