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 "sim/serialize.hh" 49#include "sim/sim_object.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 /* Set the traversal order for further iterators */ 419 objectsInOrder.clear(); 420 findTraversalOrder("root"); 421} 422 423void 424CxxConfigManager::findTraversalOrder(const std::string &object_name) 425{ 426 SimObject *object = findObject(object_name); 427 428 if (object) { 429 objectsInOrder.push_back(object); 430 431 std::vector<std::string> children; 432 configFile.getObjectChildren(object_name, children, true); 433 434 /* Visit all your children */ 435 for (auto i = children.begin(); i != children.end(); ++i) 436 findTraversalOrder(*i); 437 } 438} 439 440void 441CxxConfigManager::bindAllPorts() 442{ 443 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++i) 444 bindObjectPorts(*i); 445} 446 447void 448CxxConfigManager::bindPort( 449 SimObject *master_object, const std::string &master_port_name, 450 PortID master_port_index, 451 SimObject *slave_object, const std::string &slave_port_name, 452 PortID slave_port_index) 453{ 454 /* FIXME, check slave_port_index against connection_count 455 * defined for port, need getPortConnectionCount and a 456 * getCxxConfigDirectoryEntry for each object. */ 457 458 /* It would be nice to be able to catch the errors from these calls. */ 459 Port &master_port = master_object->getPort( 460 master_port_name, master_port_index); 461 Port &slave_port = slave_object->getPort( 462 slave_port_name, slave_port_index); 463 464 if (master_port.isConnected()) { 465 throw Exception(master_object->name(), csprintf( 466 "Master port: %s[%d] is already connected\n", master_port_name, 467 master_port_index)); 468 } 469 470 if (slave_port.isConnected()) { 471 throw Exception(slave_object->name(), csprintf( 472 "Slave port: %s[%d] is already connected\n", slave_port_name, 473 slave_port_index)); 474 } 475 476 DPRINTF(CxxConfig, "Binding port %s.%s[%d]" 477 " to %s:%s[%d]\n", 478 master_object->name(), master_port_name, master_port_index, 479 slave_object->name(), slave_port_name, slave_port_index); 480 481 master_port.bind(slave_port); 482} 483 484void 485CxxConfigManager::bindMasterPort(SimObject *object, 486 const CxxConfigDirectoryEntry::PortDesc &port, 487 const std::vector<std::string> &peers) 488{ 489 unsigned int master_port_index = 0; 490 491 for (auto peer_i = peers.begin(); peer_i != peers.end(); 492 ++peer_i) 493 { 494 const std::string &peer = *peer_i; 495 std::string slave_object_name; 496 std::string slave_port_name; 497 unsigned int slave_port_index; 498 499 parsePort(peer, slave_object_name, slave_port_name, 500 slave_port_index); 501 502 std::string slave_instance_name = rename(slave_object_name); 503 504 if (objectsByName.find(slave_instance_name) == objectsByName.end()) { 505 throw Exception(object->name(), csprintf( 506 "Can't find slave port object: %s", slave_instance_name)); 507 } 508 509 SimObject *slave_object = objectsByName[slave_instance_name]; 510 511 bindPort(object, port.name, master_port_index, 512 slave_object, slave_port_name, slave_port_index); 513 514 master_port_index++; 515 } 516} 517 518void 519CxxConfigManager::bindObjectPorts(SimObject *object) 520{ 521 /* We may want to separate object->name() from the name in configuration 522 * later to allow (for example) repetition of fragments of configs */ 523 const std::string &instance_name = object->name(); 524 525 std::string object_name = unRename(instance_name); 526 527 std::string object_type; 528 const CxxConfigDirectoryEntry &entry = 529 findObjectType(object_name, object_type); 530 531 DPRINTF(CxxConfig, "Binding ports of object: %s (%s)\n", 532 instance_name, object_type); 533 534 for (auto i = entry.ports.begin(); i != entry.ports.end(); ++i) { 535 const CxxConfigDirectoryEntry::PortDesc *port = (*i).second; 536 537 DPRINTF(CxxConfig, "Binding port: %s.%s\n", instance_name, 538 port->name); 539 540 std::vector<std::string> peers; 541 configFile.getPortPeers(object_name, port->name, peers); 542 543 /* Only handle master ports as binding only needs to happen once 544 * for each observed pair of ports */ 545 if (port->isMaster) { 546 if (!port->isVector && peers.size() > 1) { 547 throw Exception(instance_name, csprintf( 548 "Too many connections to non-vector port %s (%d)\n", 549 port->name, peers.size())); 550 } 551 552 bindMasterPort(object, *port, peers); 553 } 554 } 555} 556 557void 558CxxConfigManager::parsePort(const std::string &inp, 559 std::string &path, std::string &port, unsigned int &index) 560{ 561 std::size_t dot_i = inp.rfind('.'); 562 std::size_t open_square_i = inp.rfind('['); 563 564 if (dot_i == std::string::npos) { 565 DPRINTF(CxxConfig, "Bad port string: %s\n", inp); 566 path = ""; 567 port = ""; 568 index = 0; 569 } else { 570 path = std::string(inp, 0, dot_i); 571 572 if (open_square_i == std::string::npos) { 573 /* Singleton port */ 574 port = std::string(inp, dot_i + 1, inp.length() - dot_i); 575 index = 0; 576 } else { 577 /* Vectored port elemnt */ 578 port = std::string(inp, dot_i + 1, (open_square_i - 1) - dot_i); 579 index = std::atoi(inp.c_str() + open_square_i + 1); 580 } 581 } 582} 583 584void 585CxxConfigManager::forEachObject(void (SimObject::*mem_func)()) 586{ 587 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++i) 588 ((*i)->*mem_func)(); 589} 590 591void 592CxxConfigManager::instantiate(bool build_all) 593{ 594 if (build_all) { 595 findAllObjects(); 596 bindAllPorts(); 597 } 598 599 DPRINTF(CxxConfig, "Initialising all objects\n"); 600 forEachObject(&SimObject::init); 601 602 DPRINTF(CxxConfig, "Registering stats\n"); 603 forEachObject(&SimObject::regStats); 604 605 DPRINTF(CxxConfig, "Registering probe points\n"); 606 forEachObject(&SimObject::regProbePoints); 607 608 DPRINTF(CxxConfig, "Connecting probe listeners\n"); 609 forEachObject(&SimObject::regProbeListeners); 610} 611 612void 613CxxConfigManager::initState() 614{ 615 DPRINTF(CxxConfig, "Calling initState on all objects\n"); 616 forEachObject(&SimObject::initState); 617} 618 619void 620CxxConfigManager::startup() 621{ 622 DPRINTF(CxxConfig, "Starting up all objects\n"); 623 forEachObject(&SimObject::startup); 624} 625 626unsigned int 627CxxConfigManager::drain() 628{ 629 return DrainManager::instance().tryDrain() ? 0 : 1; 630} 631 632void 633CxxConfigManager::drainResume() 634{ 635 DrainManager::instance().resume(); 636} 637 638void 639CxxConfigManager::serialize(std::ostream &os) 640{ 641 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++ i) { 642 // (*i)->nameOut(os); FIXME, change access spec. for nameOut 643 os << '[' << (*i)->name() << "]\n"; 644 (*i)->serialize(os); 645 } 646} 647 648void 649CxxConfigManager::loadState(CheckpointIn &checkpoint) 650{ 651 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++ i) 652 (*i)->loadState(checkpoint); 653} 654 655void 656CxxConfigManager::deleteObjects() 657{ 658 for (auto i = objectsInOrder.rbegin(); i != objectsInOrder.rend(); ++i) { 659 DPRINTF(CxxConfig, "Freeing sim object: %s\n", (*i)->name()); 660 delete *i; 661 } 662 663 for (auto i = objectParamsByName.rbegin(); 664 i != objectParamsByName.rend(); ++i) 665 { 666 CxxConfigParams *params = (*i).second; 667 668 DPRINTF(CxxConfig, "Freeing sim object params: %s\n", 669 params->getName()); 670 delete params; 671 } 672 673 objectsInOrder.clear(); 674 objectsByName.clear(); 675} 676 677void 678CxxConfigManager::setParam(const std::string &object_name, 679 const std::string ¶m_name, const std::string ¶m_value) 680{ 681 CxxConfigParams *params = findObjectParams(object_name); 682 683 if (!params->setParam(param_name, param_value, flags)) { 684 throw Exception(object_name, csprintf("Bad parameter value:" 685 " .%s=X=\"%s\"", param_name, param_value)); 686 } else { 687 std::string instance_name = rename(object_name); 688 689 DPRINTF(CxxConfig, "Setting parameter %s.%s=%s\n", 690 instance_name, param_name, param_value); 691 } 692} 693 694void 695CxxConfigManager::setParamVector(const std::string &object_name, 696 const std::string ¶m_name, 697 const std::vector<std::string> ¶m_values) 698{ 699 CxxConfigParams *params = findObjectParams(object_name); 700 701 if (!params->setParamVector(param_name, param_values, flags)) { 702 throw Exception(object_name, csprintf("Bad vector parameter value:" 703 " .%s=X=\"%s\"", param_name, formatParamList(param_values))); 704 } else { 705 std::string instance_name = rename(object_name); 706 707 DPRINTF(CxxConfig, "Setting parameter %s.%s=\"%s\"\n", 708 instance_name, param_name, formatParamList(param_values)); 709 } 710} 711 712void CxxConfigManager::addRenaming(const Renaming &renaming) 713{ 714 renamings.push_back(renaming); 715} 716