cxx_manager.cc revision 10905:a6ca6831e775
1/* 2 * Copyright (c) 2014 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Andrew Bardsley 38 */ 39 40#include <cstdlib> 41#include <sstream> 42 43#include "base/str.hh" 44#include "debug/CxxConfig.hh" 45#include "mem/mem_object.hh" 46#include "sim/cxx_manager.hh" 47#include "sim/serialize.hh" 48 49CxxConfigManager::CxxConfigManager(CxxConfigFileBase &configFile_) : 50 configFile(configFile_), flags(configFile_.getFlags()), 51 simObjectResolver(*this) 52{ 53} 54 55const CxxConfigDirectoryEntry & 56CxxConfigManager::findObjectType(const std::string &object_name, 57 std::string &object_type) 58{ 59 if (!configFile.objectExists(object_name)) 60 throw Exception(object_name, "Can't find sim object"); 61 62 if (!configFile.getParam(object_name, "type", object_type)) 63 throw Exception(object_name, "Sim object has no 'type' field"); 64 65 if (cxx_config_directory.find(object_type) == 66 cxx_config_directory.end()) 67 { 68 throw Exception(object_name, csprintf( 69 "No sim object type %s is available", object_type)); 70 } 71 72 const CxxConfigDirectoryEntry *entry = cxx_config_directory[object_type]; 73 74 return *entry; 75} 76 77std::string 78CxxConfigManager::rename(const std::string &from_name) 79{ 80 for (auto i = renamings.begin(); i != renamings.end(); ++ i) { 81 const Renaming &renaming = *i; 82 83 if (from_name.find(renaming.fromPrefix) == 0) { 84 return renaming.toPrefix + 85 from_name.substr(renaming.fromPrefix.length()); 86 } 87 } 88 89 return from_name; 90} 91 92std::string 93CxxConfigManager::unRename(const std::string &to_name) 94{ 95 for (auto i = renamings.begin(); i != renamings.end(); ++ i) { 96 const Renaming &renaming = *i; 97 98 if (to_name.find(renaming.toPrefix) == 0) { 99 return renaming.fromPrefix + 100 to_name.substr(renaming.toPrefix.length()); 101 } 102 } 103 104 return to_name; 105} 106 107static 108std::string formatParamList(const std::vector<std::string> ¶m_values) 109{ 110 std::ostringstream params; 111 112 auto i = param_values.begin(); 113 auto end_i = param_values.end(); 114 115 params << '['; 116 while (i != end_i) { 117 params << (*i); 118 ++i; 119 120 if (i != end_i) 121 params << ", "; 122 } 123 params << ']'; 124 125 return params.str(); 126} 127 128SimObject * 129CxxConfigManager::findObject(const std::string &object_name, 130 bool visit_children) 131{ 132 std::string instance_name = rename(object_name); 133 134 if (object_name == "Null") 135 return NULL; 136 137 /* Already constructed */ 138 if (objectsByName.find(instance_name) != objectsByName.end()) 139 return objectsByName[instance_name]; 140 141 if (inVisit.find(instance_name) != inVisit.end()) 142 throw Exception(instance_name, "Cycle in configuration"); 143 144 std::string object_type; 145 const CxxConfigDirectoryEntry &entry = 146 findObjectType(object_name, object_type); 147 148 SimObject *object = NULL; 149 150 CxxConfigParams *object_params = findObjectParams(object_name); 151 152 try { 153 DPRINTF(CxxConfig, "Configuring sim object references for: %s" 154 " (%s from object %s)\n", instance_name, object_type, 155 object_name); 156 157 /* Remember the path back to the top of the recursion to detect 158 * cycles */ 159 inVisit.insert(instance_name); 160 161 /* Resolve pointed-to SimObjects by recursing into them */ 162 for (auto i = entry.parameters.begin(); 163 i != entry.parameters.end(); ++i) 164 { 165 const CxxConfigDirectoryEntry::ParamDesc *param = (*i).second; 166 167 if (param->isSimObject) { 168 if (param->isVector) { 169 std::vector<std::string> sub_object_names; 170 171 if (!configFile.getParamVector(object_name, param->name, 172 sub_object_names)) 173 { 174 throw Exception(object_name, csprintf( 175 "Element not found: %s", param->name)); 176 } 177 178 std::vector<SimObject *> sub_objects; 179 180 for (auto n = sub_object_names.begin(); 181 n != sub_object_names.end(); ++n) 182 { 183 SimObject *sub_object = findObject(*n, 184 visit_children); 185 186 if (sub_object) 187 sub_objects.push_back(sub_object); 188 } 189 190 if (!object_params->setSimObjectVector(param->name, 191 sub_objects)) 192 { 193 throw Exception(object_name, csprintf( 194 "Can't assign sim object element %s from \"%s\"", 195 param->name, formatParamList(sub_object_names))); 196 } 197 198 DPRINTF(CxxConfig, "Setting sim object(s): %s.%s=%s\n", 199 object_name, param->name, 200 formatParamList(sub_object_names)); 201 } else { 202 std::string sub_object_name; 203 204 if (!configFile.getParam(object_name, param->name, 205 sub_object_name)) 206 { 207 throw Exception(object_name, csprintf( 208 "Element not found: %s", param->name)); 209 } 210 211 SimObject *sub_object = findObject(sub_object_name, 212 visit_children); 213 214 if (sub_object) { 215 if (!object_params->setSimObject(param->name, 216 sub_object)) 217 { 218 throw Exception(object_name, csprintf( 219 "Can't assign sim object element %s from" 220 " \"%s\"", param->name, sub_object_name)); 221 } 222 } 223 224 DPRINTF(CxxConfig, "Setting sim object(s):" 225 " %s.%s=%s\n", object_name, param->name, 226 sub_object_name); 227 } 228 } 229 } 230 231 DPRINTF(CxxConfig, "Creating SimObject: %s\n", instance_name); 232 object = object_params->simObjectCreate(); 233 234 if (!object) { 235 throw Exception(object_name, csprintf("Couldn't create object of" 236 " type: %s", object_type)); 237 } 238 239 objectsByName[instance_name] = object; 240 objectParamsByName[instance_name] = object_params; 241 242 if (visit_children) { 243 std::vector<std::string> children; 244 configFile.getObjectChildren(object_name, children, true); 245 246 /* Visit all your children */ 247 for (auto i = children.begin(); i != children.end(); ++i) 248 findObject(*i, visit_children); 249 } 250 } catch (Exception &) { 251 delete object_params; 252 throw; 253 } 254 255 /* Mark that we've exited object 256 * construction and so 'find'ing this object again won't be a 257 * configuration loop */ 258 inVisit.erase(object_name); 259 return object; 260} 261 262CxxConfigParams * 263CxxConfigManager::findObjectParams(const std::string &object_name) 264{ 265 std::string instance_name = rename(object_name); 266 267 /* Already constructed */ 268 if (objectParamsByName.find(instance_name) != objectParamsByName.end()) 269 return objectParamsByName[instance_name]; 270 271 std::string object_type; 272 const CxxConfigDirectoryEntry &entry = 273 findObjectType(object_name, object_type); 274 275 DPRINTF(CxxConfig, "Configuring parameters of object: %s (%s)\n", 276 instance_name, object_type); 277 278 CxxConfigParams *object_params = entry.makeParamsObject(); 279 280 try { 281 /* Fill in the implicit parameters that don't necessarily 282 * appear in config files */ 283 object_params->setName(instance_name); 284 285 /* Fill in parameters */ 286 for (auto i = entry.parameters.begin(); 287 i != entry.parameters.end(); ++i) 288 { 289 const CxxConfigDirectoryEntry::ParamDesc *param = (*i).second; 290 291 if (!param->isSimObject) { 292 /* Only handle non-SimObject parameters here (see below) */ 293 294 if (param->isVector) { 295 std::vector<std::string> param_values; 296 297 if (!configFile.getParamVector(object_name, param->name, 298 param_values)) 299 { 300 throw Exception(object_name, csprintf( 301 "Element not found for parameter: %s", 302 param->name)); 303 } 304 305 if (!object_params->setParamVector(param->name, 306 param_values, flags)) 307 { 308 throw Exception(instance_name, csprintf( 309 "Bad parameter value: .%s=X=\"%s\"", 310 param->name, formatParamList(param_values))); 311 } 312 313 DPRINTF(CxxConfig, "Setting parameter" 314 " %s.%s=%s\n", instance_name, param->name, 315 formatParamList(param_values)); 316 } else { 317 std::string param_value; 318 319 if (!configFile.getParam(object_name, param->name, 320 param_value)) 321 { 322 throw Exception(object_name, csprintf( 323 "Element not found for parameter: %s", 324 param->name)); 325 } 326 327 if (!object_params->setParam(param->name, param_value, 328 flags)) 329 { 330 throw Exception(instance_name, csprintf( 331 "Bad parameter value: .%s=X=\"%s\"", 332 param->name, param_value)); 333 } 334 335 DPRINTF(CxxConfig, "Setting parameter %s.%s=%s\n", 336 instance_name, param->name, param_value); 337 } 338 } 339 } 340 341 /* Find the number of ports that will need binding and set the 342 * appropriate port_..._connection_count parameters */ 343 for (auto i = entry.ports.begin(); i != entry.ports.end(); ++i) { 344 const CxxConfigDirectoryEntry::PortDesc *port = (*i).second; 345 std::vector<std::string> peers; 346 347 if (!configFile.getPortPeers(object_name, port->name, peers)) { 348 DPRINTF(CxxConfig, "Port not found: %s.%s," 349 " assuming there are no connections\n", 350 instance_name, port->name); 351 } 352 353 unsigned int peer_count = peers.size(); 354 355 /* It would be more efficient to split the peer list and 356 * save the values for peer binding later but that would 357 * require another annoying intermediate structure to 358 * hold for little performance increase */ 359 360 if (!object_params->setPortConnectionCount(port->name, 361 peer_count)) 362 { 363 throw Exception(instance_name, csprintf( 364 "Unconnected port: %s", port->name)); 365 } 366 367 DPRINTF(CxxConfig, "Setting port connection count" 368 " for: %s.%s to %d\n", 369 instance_name, port->name, peer_count); 370 } 371 372 /* Set pointed-to SimObjects to NULL */ 373 for (auto i = entry.parameters.begin(); 374 i != entry.parameters.end(); ++i) 375 { 376 const CxxConfigDirectoryEntry::ParamDesc *param = (*i).second; 377 378 if (param->isSimObject) { 379 bool ret; 380 381 DPRINTF(CxxConfig, "Nulling sim object reference: %s.%s\n", 382 instance_name, param->name); 383 384 if (param->isVector) { 385 /* Clear the reference list. */ 386 std::vector<SimObject *> empty; 387 ret = object_params->setSimObjectVector(param->name, 388 empty); 389 } else { 390 ret = object_params->setSimObject(param->name, NULL); 391 } 392 393 if (!ret) { 394 throw Exception(instance_name, csprintf( 395 "Error nulling sim object reference(s): %s", 396 param->name)); 397 } 398 } 399 } 400 } catch (Exception &) { 401 delete object_params; 402 throw; 403 } 404 405 objectParamsByName[instance_name] = object_params; 406 407 return object_params; 408} 409 410void 411CxxConfigManager::findAllObjects() 412{ 413 std::vector<std::string> objects; 414 configFile.getAllObjectNames(objects); 415 416 /* Sort the object names to get a consistent initialisation order 417 * even with config file reorganisation */ 418 std::sort(objects.begin(), objects.end()); 419 420 for (auto i = objects.begin(); i != objects.end(); ++i) 421 findObject(*i); 422 423 /* Set the traversal order for further iterators */ 424 objectsInOrder.clear(); 425 findTraversalOrder("root"); 426} 427 428void 429CxxConfigManager::findTraversalOrder(const std::string &object_name) 430{ 431 SimObject *object = findObject(object_name); 432 433 if (object) { 434 objectsInOrder.push_back(object); 435 436 std::vector<std::string> children; 437 configFile.getObjectChildren(object_name, children, true); 438 439 /* Visit all your children */ 440 for (auto i = children.begin(); i != children.end(); ++i) 441 findTraversalOrder(*i); 442 } 443} 444 445void 446CxxConfigManager::bindAllPorts() 447{ 448 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++i) 449 bindObjectPorts(*i); 450} 451 452void 453CxxConfigManager::bindPort( 454 SimObject *master_object, const std::string &master_port_name, 455 PortID master_port_index, 456 SimObject *slave_object, const std::string &slave_port_name, 457 PortID slave_port_index) 458{ 459 MemObject *master_mem_object = dynamic_cast<MemObject *>(master_object); 460 MemObject *slave_mem_object = dynamic_cast<MemObject *>(slave_object); 461 462 if (!master_mem_object) { 463 throw Exception(master_object->name(), csprintf( 464 "Object isn't a mem object and so can have master port:" 465 " %s[%d]", master_port_name, master_port_index)); 466 } 467 468 if (!slave_mem_object) { 469 throw Exception(slave_object->name(), csprintf( 470 "Object isn't a mem object and so can have slave port:" 471 " %s[%d]", slave_port_name, slave_port_index)); 472 } 473 474 /* FIXME, check slave_port_index against connection_count 475 * defined for port, need getPortConnectionCount and a 476 * getCxxConfigDirectoryEntry for each object. */ 477 478 /* It would be nice to be able to catch the errors from these calls. */ 479 BaseMasterPort &master_port = master_mem_object->getMasterPort( 480 master_port_name, master_port_index); 481 BaseSlavePort &slave_port = slave_mem_object->getSlavePort( 482 slave_port_name, slave_port_index); 483 484 if (master_port.isConnected()) { 485 throw Exception(master_object->name(), csprintf( 486 "Master port: %s[%d] is already connected\n", master_port_name, 487 master_port_index)); 488 } 489 490 if (slave_port.isConnected()) { 491 throw Exception(slave_object->name(), csprintf( 492 "Slave port: %s[%d] is already connected\n", slave_port_name, 493 slave_port_index)); 494 } 495 496 DPRINTF(CxxConfig, "Binding port %s.%s[%d]" 497 " to %s:%s[%d]\n", 498 master_object->name(), master_port_name, master_port_index, 499 slave_object->name(), slave_port_name, slave_port_index); 500 501 master_port.bind(slave_port); 502} 503 504void 505CxxConfigManager::bindMasterPort(SimObject *object, 506 const CxxConfigDirectoryEntry::PortDesc &port, 507 const std::vector<std::string> &peers) 508{ 509 unsigned int master_port_index = 0; 510 511 for (auto peer_i = peers.begin(); peer_i != peers.end(); 512 ++peer_i) 513 { 514 const std::string &peer = *peer_i; 515 std::string slave_object_name; 516 std::string slave_port_name; 517 unsigned int slave_port_index; 518 519 parsePort(peer, slave_object_name, slave_port_name, 520 slave_port_index); 521 522 std::string slave_instance_name = rename(slave_object_name); 523 524 if (objectsByName.find(slave_instance_name) == objectsByName.end()) { 525 throw Exception(object->name(), csprintf( 526 "Can't find slave port object: %s", slave_instance_name)); 527 } 528 529 SimObject *slave_object = objectsByName[slave_instance_name]; 530 531 bindPort(object, port.name, master_port_index, 532 slave_object, slave_port_name, slave_port_index); 533 534 master_port_index++; 535 } 536} 537 538void 539CxxConfigManager::bindObjectPorts(SimObject *object) 540{ 541 /* We may want to separate object->name() from the name in configuration 542 * later to allow (for example) repetition of fragments of configs */ 543 const std::string &instance_name = object->name(); 544 545 std::string object_name = unRename(instance_name); 546 547 std::string object_type; 548 const CxxConfigDirectoryEntry &entry = 549 findObjectType(object_name, object_type); 550 551 DPRINTF(CxxConfig, "Binding ports of object: %s (%s)\n", 552 instance_name, object_type); 553 554 for (auto i = entry.ports.begin(); i != entry.ports.end(); ++i) { 555 const CxxConfigDirectoryEntry::PortDesc *port = (*i).second; 556 557 DPRINTF(CxxConfig, "Binding port: %s.%s\n", instance_name, 558 port->name); 559 560 std::vector<std::string> peers; 561 configFile.getPortPeers(object_name, port->name, peers); 562 563 /* Only handle master ports as binding only needs to happen once 564 * for each observed pair of ports */ 565 if (port->isMaster) { 566 if (!port->isVector && peers.size() > 1) { 567 throw Exception(instance_name, csprintf( 568 "Too many connections to non-vector port %s (%d)\n", 569 port->name, peers.size())); 570 } 571 572 bindMasterPort(object, *port, peers); 573 } 574 } 575} 576 577void 578CxxConfigManager::parsePort(const std::string &inp, 579 std::string &path, std::string &port, unsigned int &index) 580{ 581 std::size_t dot_i = inp.rfind('.'); 582 std::size_t open_square_i = inp.rfind('['); 583 584 if (dot_i == std::string::npos) { 585 DPRINTF(CxxConfig, "Bad port string: %s\n", inp); 586 path = ""; 587 port = ""; 588 index = 0; 589 } else { 590 path = std::string(inp, 0, dot_i); 591 592 if (open_square_i == std::string::npos) { 593 /* Singleton port */ 594 port = std::string(inp, dot_i + 1, inp.length() - dot_i); 595 index = 0; 596 } else { 597 /* Vectored port elemnt */ 598 port = std::string(inp, dot_i + 1, (open_square_i - 1) - dot_i); 599 index = std::atoi(inp.c_str() + open_square_i + 1); 600 } 601 } 602} 603 604void 605CxxConfigManager::forEachObject(void (SimObject::*mem_func)()) 606{ 607 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++i) 608 ((*i)->*mem_func)(); 609} 610 611void 612CxxConfigManager::instantiate(bool build_all) 613{ 614 if (build_all) { 615 findAllObjects(); 616 bindAllPorts(); 617 } 618 619 DPRINTF(CxxConfig, "Initialising all objects\n"); 620 forEachObject(&SimObject::init); 621 622 DPRINTF(CxxConfig, "Registering stats\n"); 623 forEachObject(&SimObject::regStats); 624 625 DPRINTF(CxxConfig, "Registering probe points\n"); 626 forEachObject(&SimObject::regProbePoints); 627 628 DPRINTF(CxxConfig, "Connecting probe listeners\n"); 629 forEachObject(&SimObject::regProbeListeners); 630} 631 632void 633CxxConfigManager::initState() 634{ 635 DPRINTF(CxxConfig, "Calling initState on all objects\n"); 636 forEachObject(&SimObject::initState); 637} 638 639void 640CxxConfigManager::startup() 641{ 642 DPRINTF(CxxConfig, "Starting up all objects\n"); 643 forEachObject(&SimObject::startup); 644} 645 646unsigned int 647CxxConfigManager::drain(DrainManager *drain_manager) 648{ 649 unsigned int ret = 0; 650 651 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++ i) 652 ret += (*i)->drain(drain_manager); 653 654 return ret; 655} 656 657void 658CxxConfigManager::drainResume() 659{ 660 forEachObject(&SimObject::drainResume); 661} 662 663void 664CxxConfigManager::serialize(std::ostream &os) 665{ 666 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++ i) { 667 // (*i)->nameOut(os); FIXME, change access spec. for nameOut 668 os << '[' << (*i)->name() << "]\n"; 669 (*i)->serialize(os); 670 } 671} 672 673void 674CxxConfigManager::loadState(CheckpointIn &checkpoint) 675{ 676 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++ i) 677 (*i)->loadState(checkpoint); 678} 679 680void 681CxxConfigManager::deleteObjects() 682{ 683 for (auto i = objectsInOrder.rbegin(); i != objectsInOrder.rend(); ++i) { 684 DPRINTF(CxxConfig, "Freeing sim object: %s\n", (*i)->name()); 685 delete *i; 686 } 687 688 for (auto i = objectParamsByName.rbegin(); 689 i != objectParamsByName.rend(); ++i) 690 { 691 CxxConfigParams *params = (*i).second; 692 693 DPRINTF(CxxConfig, "Freeing sim object params: %s\n", 694 params->getName()); 695 delete params; 696 } 697 698 objectsInOrder.clear(); 699 objectsByName.clear(); 700} 701 702void 703CxxConfigManager::setParam(const std::string &object_name, 704 const std::string ¶m_name, const std::string ¶m_value) 705{ 706 CxxConfigParams *params = findObjectParams(object_name); 707 708 if (!params->setParam(param_name, param_value, flags)) { 709 throw Exception(object_name, csprintf("Bad parameter value:" 710 " .%s=X=\"%s\"", param_name, param_value)); 711 } else { 712 std::string instance_name = rename(object_name); 713 714 DPRINTF(CxxConfig, "Setting parameter %s.%s=%s\n", 715 instance_name, param_name, param_value); 716 } 717} 718 719void 720CxxConfigManager::setParamVector(const std::string &object_name, 721 const std::string ¶m_name, 722 const std::vector<std::string> ¶m_values) 723{ 724 CxxConfigParams *params = findObjectParams(object_name); 725 726 if (!params->setParamVector(param_name, param_values, flags)) { 727 throw Exception(object_name, csprintf("Bad vector parameter value:" 728 " .%s=X=\"%s\"", param_name, formatParamList(param_values))); 729 } else { 730 std::string instance_name = rename(object_name); 731 732 DPRINTF(CxxConfig, "Setting parameter %s.%s=\"%s\"\n", 733 instance_name, param_name, formatParamList(param_values)); 734 } 735} 736 737void CxxConfigManager::addRenaming(const Renaming &renaming) 738{ 739 renamings.push_back(renaming); 740} 741