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