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