2 * Copyright (c) 2014 ARM Limited
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.
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.
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.
37 * Authors: Andrew Bardsley
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"
49 CxxConfigManager::CxxConfigManager(CxxConfigFileBase
&configFile_
) :
50 configFile(configFile_
), flags(configFile_
.getFlags()),
51 simObjectResolver(*this)
55 const CxxConfigDirectoryEntry
&
56 CxxConfigManager::findObjectType(const std::string
&object_name
,
57 std::string
&object_type
)
59 if (!configFile
.objectExists(object_name
))
60 throw Exception(object_name
, "Can't find sim object");
62 if (!configFile
.getParam(object_name
, "type", object_type
))
63 throw Exception(object_name
, "Sim object has no 'type' field");
65 if (cxx_config_directory
.find(object_type
) ==
66 cxx_config_directory
.end())
68 throw Exception(object_name
, csprintf(
69 "No sim object type %s is available", object_type
));
72 const CxxConfigDirectoryEntry
*entry
= cxx_config_directory
[object_type
];
78 CxxConfigManager::rename(const std::string
&from_name
)
80 for (auto i
= renamings
.begin(); i
!= renamings
.end(); ++ i
) {
81 const Renaming
&renaming
= *i
;
83 if (from_name
.find(renaming
.fromPrefix
) == 0) {
84 return renaming
.toPrefix
+
85 from_name
.substr(renaming
.fromPrefix
.length());
93 CxxConfigManager::unRename(const std::string
&to_name
)
95 for (auto i
= renamings
.begin(); i
!= renamings
.end(); ++ i
) {
96 const Renaming
&renaming
= *i
;
98 if (to_name
.find(renaming
.toPrefix
) == 0) {
99 return renaming
.fromPrefix
+
100 to_name
.substr(renaming
.toPrefix
.length());
108 std::string
formatParamList(const std::vector
<std::string
> ¶m_values
)
110 std::ostringstream params
;
112 auto i
= param_values
.begin();
113 auto end_i
= param_values
.end();
129 CxxConfigManager::findObject(const std::string
&object_name
,
132 std::string instance_name
= rename(object_name
);
134 if (object_name
== "Null")
137 /* Already constructed */
138 if (objectsByName
.find(instance_name
) != objectsByName
.end())
139 return objectsByName
[instance_name
];
141 if (inVisit
.find(instance_name
) != inVisit
.end())
142 throw Exception(instance_name
, "Cycle in configuration");
144 std::string object_type
;
145 const CxxConfigDirectoryEntry
&entry
=
146 findObjectType(object_name
, object_type
);
148 SimObject
*object
= NULL
;
150 CxxConfigParams
*object_params
= findObjectParams(object_name
);
153 DPRINTF(CxxConfig
, "Configuring sim object references for: %s"
154 " (%s from object %s)\n", instance_name
, object_type
,
157 /* Remember the path back to the top of the recursion to detect
159 inVisit
.insert(instance_name
);
161 /* Resolve pointed-to SimObjects by recursing into them */
162 for (auto i
= entry
.parameters
.begin();
163 i
!= entry
.parameters
.end(); ++i
)
165 const CxxConfigDirectoryEntry::ParamDesc
*param
= (*i
).second
;
167 if (param
->isSimObject
) {
168 if (param
->isVector
) {
169 std::vector
<std::string
> sub_object_names
;
171 if (!configFile
.getParamVector(object_name
, param
->name
,
174 throw Exception(object_name
, csprintf(
175 "Element not found: %s", param
->name
));
178 std::vector
<SimObject
*> sub_objects
;
180 for (auto n
= sub_object_names
.begin();
181 n
!= sub_object_names
.end(); ++n
)
183 SimObject
*sub_object
= findObject(*n
,
187 sub_objects
.push_back(sub_object
);
190 if (!object_params
->setSimObjectVector(param
->name
,
193 throw Exception(object_name
, csprintf(
194 "Can't assign sim object element %s from \"%s\"",
195 param
->name
, formatParamList(sub_object_names
)));
198 DPRINTF(CxxConfig
, "Setting sim object(s): %s.%s=%s\n",
199 object_name
, param
->name
,
200 formatParamList(sub_object_names
));
202 std::string sub_object_name
;
204 if (!configFile
.getParam(object_name
, param
->name
,
207 throw Exception(object_name
, csprintf(
208 "Element not found: %s", param
->name
));
211 SimObject
*sub_object
= findObject(sub_object_name
,
215 if (!object_params
->setSimObject(param
->name
,
218 throw Exception(object_name
, csprintf(
219 "Can't assign sim object element %s from"
220 " \"%s\"", param
->name
, sub_object_name
));
224 DPRINTF(CxxConfig
, "Setting sim object(s):"
225 " %s.%s=%s\n", object_name
, param
->name
,
231 DPRINTF(CxxConfig
, "Creating SimObject: %s\n", instance_name
);
232 object
= object_params
->simObjectCreate();
235 throw Exception(object_name
, csprintf("Couldn't create object of"
236 " type: %s", object_type
));
239 objectsByName
[instance_name
] = object
;
240 objectParamsByName
[instance_name
] = object_params
;
242 if (visit_children
) {
243 std::vector
<std::string
> children
;
244 configFile
.getObjectChildren(object_name
, children
, true);
246 /* Visit all your children */
247 for (auto i
= children
.begin(); i
!= children
.end(); ++i
)
248 findObject(*i
, visit_children
);
250 } catch (Exception
&) {
251 delete object_params
;
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
);
263 CxxConfigManager::findObjectParams(const std::string
&object_name
)
265 std::string instance_name
= rename(object_name
);
267 /* Already constructed */
268 if (objectParamsByName
.find(instance_name
) != objectParamsByName
.end())
269 return objectParamsByName
[instance_name
];
271 std::string object_type
;
272 const CxxConfigDirectoryEntry
&entry
=
273 findObjectType(object_name
, object_type
);
275 DPRINTF(CxxConfig
, "Configuring parameters of object: %s (%s)\n",
276 instance_name
, object_type
);
278 CxxConfigParams
*object_params
= entry
.makeParamsObject();
281 /* Fill in the implicit parameters that don't necessarily
282 * appear in config files */
283 object_params
->setName(instance_name
);
285 /* Fill in parameters */
286 for (auto i
= entry
.parameters
.begin();
287 i
!= entry
.parameters
.end(); ++i
)
289 const CxxConfigDirectoryEntry::ParamDesc
*param
= (*i
).second
;
291 if (!param
->isSimObject
) {
292 /* Only handle non-SimObject parameters here (see below) */
294 if (param
->isVector
) {
295 std::vector
<std::string
> param_values
;
297 if (!configFile
.getParamVector(object_name
, param
->name
,
300 throw Exception(object_name
, csprintf(
301 "Element not found for parameter: %s",
305 if (!object_params
->setParamVector(param
->name
,
306 param_values
, flags
))
308 throw Exception(instance_name
, csprintf(
309 "Bad parameter value: .%s=X=\"%s\"",
310 param
->name
, formatParamList(param_values
)));
313 DPRINTF(CxxConfig
, "Setting parameter"
314 " %s.%s=%s\n", instance_name
, param
->name
,
315 formatParamList(param_values
));
317 std::string param_value
;
319 if (!configFile
.getParam(object_name
, param
->name
,
322 throw Exception(object_name
, csprintf(
323 "Element not found for parameter: %s",
327 if (!object_params
->setParam(param
->name
, param_value
,
330 throw Exception(instance_name
, csprintf(
331 "Bad parameter value: .%s=X=\"%s\"",
332 param
->name
, param_value
));
335 DPRINTF(CxxConfig
, "Setting parameter %s.%s=%s\n",
336 instance_name
, param
->name
, param_value
);
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
;
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
);
353 unsigned int peer_count
= peers
.size();
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 */
360 if (!object_params
->setPortConnectionCount(port
->name
,
363 throw Exception(instance_name
, csprintf(
364 "Unconnected port: %s", port
->name
));
367 DPRINTF(CxxConfig
, "Setting port connection count"
368 " for: %s.%s to %d\n",
369 instance_name
, port
->name
, peer_count
);
372 /* Set pointed-to SimObjects to NULL */
373 for (auto i
= entry
.parameters
.begin();
374 i
!= entry
.parameters
.end(); ++i
)
376 const CxxConfigDirectoryEntry::ParamDesc
*param
= (*i
).second
;
378 if (param
->isSimObject
) {
381 DPRINTF(CxxConfig
, "Nulling sim object reference: %s.%s\n",
382 instance_name
, param
->name
);
384 if (param
->isVector
) {
385 /* Clear the reference list. */
386 std::vector
<SimObject
*> empty
;
387 ret
= object_params
->setSimObjectVector(param
->name
,
390 ret
= object_params
->setSimObject(param
->name
, NULL
);
394 throw Exception(instance_name
, csprintf(
395 "Error nulling sim object reference(s): %s",
400 } catch (Exception
&) {
401 delete object_params
;
405 objectParamsByName
[instance_name
] = object_params
;
407 return object_params
;
411 CxxConfigManager::findAllObjects()
413 std::vector
<std::string
> objects
;
414 configFile
.getAllObjectNames(objects
);
416 /* Sort the object names to get a consistent initialisation order
417 * even with config file reorganisation */
418 std::sort(objects
.begin(), objects
.end());
420 for (auto i
= objects
.begin(); i
!= objects
.end(); ++i
)
423 /* Set the traversal order for further iterators */
424 objectsInOrder
.clear();
425 findTraversalOrder("root");
429 CxxConfigManager::findTraversalOrder(const std::string
&object_name
)
431 SimObject
*object
= findObject(object_name
);
434 objectsInOrder
.push_back(object
);
436 std::vector
<std::string
> children
;
437 configFile
.getObjectChildren(object_name
, children
, true);
439 /* Visit all your children */
440 for (auto i
= children
.begin(); i
!= children
.end(); ++i
)
441 findTraversalOrder(*i
);
446 CxxConfigManager::bindAllPorts()
448 for (auto i
= objectsInOrder
.begin(); i
!= objectsInOrder
.end(); ++i
)
453 CxxConfigManager::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
)
459 MemObject
*master_mem_object
= dynamic_cast<MemObject
*>(master_object
);
460 MemObject
*slave_mem_object
= dynamic_cast<MemObject
*>(slave_object
);
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
));
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
));
474 /* FIXME, check slave_port_index against connection_count
475 * defined for port, need getPortConnectionCount and a
476 * getCxxConfigDirectoryEntry for each object. */
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
);
484 if (master_port
.isConnected()) {
485 throw Exception(master_object
->name(), csprintf(
486 "Master port: %s[%d] is already connected\n", master_port_name
,
490 if (slave_port
.isConnected()) {
491 throw Exception(slave_object
->name(), csprintf(
492 "Slave port: %s[%d] is already connected\n", slave_port_name
,
496 DPRINTF(CxxConfig
, "Binding port %s.%s[%d]"
498 master_object
->name(), master_port_name
, master_port_index
,
499 slave_object
->name(), slave_port_name
, slave_port_index
);
501 master_port
.bind(slave_port
);
505 CxxConfigManager::bindMasterPort(SimObject
*object
,
506 const CxxConfigDirectoryEntry::PortDesc
&port
,
507 const std::vector
<std::string
> &peers
)
509 unsigned int master_port_index
= 0;
511 for (auto peer_i
= peers
.begin(); peer_i
!= peers
.end();
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
;
519 parsePort(peer
, slave_object_name
, slave_port_name
,
522 std::string slave_instance_name
= rename(slave_object_name
);
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
));
529 SimObject
*slave_object
= objectsByName
[slave_instance_name
];
531 bindPort(object
, port
.name
, master_port_index
,
532 slave_object
, slave_port_name
, slave_port_index
);
539 CxxConfigManager::bindObjectPorts(SimObject
*object
)
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();
545 std::string object_name
= unRename(instance_name
);
547 std::string object_type
;
548 const CxxConfigDirectoryEntry
&entry
=
549 findObjectType(object_name
, object_type
);
551 DPRINTF(CxxConfig
, "Binding ports of object: %s (%s)\n",
552 instance_name
, object_type
);
554 for (auto i
= entry
.ports
.begin(); i
!= entry
.ports
.end(); ++i
) {
555 const CxxConfigDirectoryEntry::PortDesc
*port
= (*i
).second
;
557 DPRINTF(CxxConfig
, "Binding port: %s.%s\n", instance_name
,
560 std::vector
<std::string
> peers
;
561 configFile
.getPortPeers(object_name
, port
->name
, peers
);
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()));
572 bindMasterPort(object
, *port
, peers
);
578 CxxConfigManager::parsePort(const std::string
&inp
,
579 std::string
&path
, std::string
&port
, unsigned int &index
)
581 std::size_t dot_i
= inp
.rfind('.');
582 std::size_t open_square_i
= inp
.rfind('[');
584 if (dot_i
== std::string::npos
) {
585 DPRINTF(CxxConfig
, "Bad port string: %s\n", inp
);
590 path
= std::string(inp
, 0, dot_i
);
592 if (open_square_i
== std::string::npos
) {
594 port
= std::string(inp
, dot_i
+ 1, inp
.length() - dot_i
);
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);
605 CxxConfigManager::forEachObject(void (SimObject::*mem_func
)())
607 for (auto i
= objectsInOrder
.begin(); i
!= objectsInOrder
.end(); ++i
)
612 CxxConfigManager::instantiate(bool build_all
)
619 DPRINTF(CxxConfig
, "Initialising all objects\n");
620 forEachObject(&SimObject::init
);
622 DPRINTF(CxxConfig
, "Registering stats\n");
623 forEachObject(&SimObject::regStats
);
625 DPRINTF(CxxConfig
, "Registering probe points\n");
626 forEachObject(&SimObject::regProbePoints
);
628 DPRINTF(CxxConfig
, "Connecting probe listeners\n");
629 forEachObject(&SimObject::regProbeListeners
);
633 CxxConfigManager::initState()
635 DPRINTF(CxxConfig
, "Calling initState on all objects\n");
636 forEachObject(&SimObject::initState
);
640 CxxConfigManager::startup()
642 DPRINTF(CxxConfig
, "Starting up all objects\n");
643 forEachObject(&SimObject::startup
);
647 CxxConfigManager::drain(DrainManager
*drain_manager
)
649 unsigned int ret
= 0;
651 for (auto i
= objectsInOrder
.begin(); i
!= objectsInOrder
.end(); ++ i
)
652 ret
+= (*i
)->drain(drain_manager
);
658 CxxConfigManager::drainResume()
660 forEachObject(&SimObject::drainResume
);
664 CxxConfigManager::serialize(std::ostream
&os
)
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";
674 CxxConfigManager::loadState(Checkpoint
*checkpoint
)
676 for (auto i
= objectsInOrder
.begin(); i
!= objectsInOrder
.end(); ++ i
)
677 (*i
)->loadState(checkpoint
);
681 CxxConfigManager::deleteObjects()
683 for (auto i
= objectsInOrder
.rbegin(); i
!= objectsInOrder
.rend(); ++i
) {
684 DPRINTF(CxxConfig
, "Freeing sim object: %s\n", (*i
)->name());
688 for (auto i
= objectParamsByName
.rbegin();
689 i
!= objectParamsByName
.rend(); ++i
)
691 CxxConfigParams
*params
= (*i
).second
;
693 DPRINTF(CxxConfig
, "Freeing sim object params: %s\n",
698 objectsInOrder
.clear();
699 objectsByName
.clear();
703 CxxConfigManager::setParam(const std::string
&object_name
,
704 const std::string
¶m_name
, const std::string
¶m_value
)
706 CxxConfigParams
*params
= findObjectParams(object_name
);
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
));
712 std::string instance_name
= rename(object_name
);
714 DPRINTF(CxxConfig
, "Setting parameter %s.%s=%s\n",
715 instance_name
, param_name
, param_value
);
720 CxxConfigManager::setParamVector(const std::string
&object_name
,
721 const std::string
¶m_name
,
722 const std::vector
<std::string
> ¶m_values
)
724 CxxConfigParams
*params
= findObjectParams(object_name
);
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
)));
730 std::string instance_name
= rename(object_name
);
732 DPRINTF(CxxConfig
, "Setting parameter %s.%s=\"%s\"\n",
733 instance_name
, param_name
, formatParamList(param_values
));
737 void CxxConfigManager::addRenaming(const Renaming
&renaming
)
739 renamings
.push_back(renaming
);