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.
38 #include "sim/cxx_manager.hh"
43 #include "base/str.hh"
44 #include "base/trace.hh"
45 #include "debug/CxxConfig.hh"
46 #include "sim/serialize.hh"
47 #include "sim/sim_object.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 /* Set the traversal order for further iterators */
417 objectsInOrder
.clear();
418 findTraversalOrder("root");
422 CxxConfigManager::findTraversalOrder(const std::string
&object_name
)
424 SimObject
*object
= findObject(object_name
);
427 objectsInOrder
.push_back(object
);
429 std::vector
<std::string
> children
;
430 configFile
.getObjectChildren(object_name
, children
, true);
432 /* Visit all your children */
433 for (auto i
= children
.begin(); i
!= children
.end(); ++i
)
434 findTraversalOrder(*i
);
439 CxxConfigManager::bindAllPorts()
441 for (auto i
= objectsInOrder
.begin(); i
!= objectsInOrder
.end(); ++i
)
446 CxxConfigManager::bindPort(
447 SimObject
*master_object
, const std::string
&master_port_name
,
448 PortID master_port_index
,
449 SimObject
*slave_object
, const std::string
&slave_port_name
,
450 PortID slave_port_index
)
452 /* FIXME, check slave_port_index against connection_count
453 * defined for port, need getPortConnectionCount and a
454 * getCxxConfigDirectoryEntry for each object. */
456 /* It would be nice to be able to catch the errors from these calls. */
457 Port
&master_port
= master_object
->getPort(
458 master_port_name
, master_port_index
);
459 Port
&slave_port
= slave_object
->getPort(
460 slave_port_name
, slave_port_index
);
462 if (master_port
.isConnected()) {
463 throw Exception(master_object
->name(), csprintf(
464 "Master port: %s[%d] is already connected\n", master_port_name
,
468 if (slave_port
.isConnected()) {
469 throw Exception(slave_object
->name(), csprintf(
470 "Slave port: %s[%d] is already connected\n", slave_port_name
,
474 DPRINTF(CxxConfig
, "Binding port %s.%s[%d]"
476 master_object
->name(), master_port_name
, master_port_index
,
477 slave_object
->name(), slave_port_name
, slave_port_index
);
479 master_port
.bind(slave_port
);
483 CxxConfigManager::bindMasterPort(SimObject
*object
,
484 const CxxConfigDirectoryEntry::PortDesc
&port
,
485 const std::vector
<std::string
> &peers
)
487 unsigned int master_port_index
= 0;
489 for (auto peer_i
= peers
.begin(); peer_i
!= peers
.end();
492 const std::string
&peer
= *peer_i
;
493 std::string slave_object_name
;
494 std::string slave_port_name
;
495 unsigned int slave_port_index
;
497 parsePort(peer
, slave_object_name
, slave_port_name
,
500 std::string slave_instance_name
= rename(slave_object_name
);
502 if (objectsByName
.find(slave_instance_name
) == objectsByName
.end()) {
503 throw Exception(object
->name(), csprintf(
504 "Can't find slave port object: %s", slave_instance_name
));
507 SimObject
*slave_object
= objectsByName
[slave_instance_name
];
509 bindPort(object
, port
.name
, master_port_index
,
510 slave_object
, slave_port_name
, slave_port_index
);
517 CxxConfigManager::bindObjectPorts(SimObject
*object
)
519 /* We may want to separate object->name() from the name in configuration
520 * later to allow (for example) repetition of fragments of configs */
521 const std::string
&instance_name
= object
->name();
523 std::string object_name
= unRename(instance_name
);
525 std::string object_type
;
526 const CxxConfigDirectoryEntry
&entry
=
527 findObjectType(object_name
, object_type
);
529 DPRINTF(CxxConfig
, "Binding ports of object: %s (%s)\n",
530 instance_name
, object_type
);
532 for (auto i
= entry
.ports
.begin(); i
!= entry
.ports
.end(); ++i
) {
533 const CxxConfigDirectoryEntry::PortDesc
*port
= (*i
).second
;
535 DPRINTF(CxxConfig
, "Binding port: %s.%s\n", instance_name
,
538 std::vector
<std::string
> peers
;
539 configFile
.getPortPeers(object_name
, port
->name
, peers
);
541 /* Only handle master ports as binding only needs to happen once
542 * for each observed pair of ports */
543 if (port
->isMaster
) {
544 if (!port
->isVector
&& peers
.size() > 1) {
545 throw Exception(instance_name
, csprintf(
546 "Too many connections to non-vector port %s (%d)\n",
547 port
->name
, peers
.size()));
550 bindMasterPort(object
, *port
, peers
);
556 CxxConfigManager::parsePort(const std::string
&inp
,
557 std::string
&path
, std::string
&port
, unsigned int &index
)
559 std::size_t dot_i
= inp
.rfind('.');
560 std::size_t open_square_i
= inp
.rfind('[');
562 if (dot_i
== std::string::npos
) {
563 DPRINTF(CxxConfig
, "Bad port string: %s\n", inp
);
568 path
= std::string(inp
, 0, dot_i
);
570 if (open_square_i
== std::string::npos
) {
572 port
= std::string(inp
, dot_i
+ 1, inp
.length() - dot_i
);
575 /* Vectored port elemnt */
576 port
= std::string(inp
, dot_i
+ 1, (open_square_i
- 1) - dot_i
);
577 index
= std::atoi(inp
.c_str() + open_square_i
+ 1);
583 CxxConfigManager::forEachObject(void (SimObject::*mem_func
)())
585 for (auto i
= objectsInOrder
.begin(); i
!= objectsInOrder
.end(); ++i
)
590 CxxConfigManager::instantiate(bool build_all
)
597 DPRINTF(CxxConfig
, "Initialising all objects\n");
598 forEachObject(&SimObject::init
);
600 DPRINTF(CxxConfig
, "Registering stats\n");
601 forEachObject(&SimObject::regStats
);
603 DPRINTF(CxxConfig
, "Registering probe points\n");
604 forEachObject(&SimObject::regProbePoints
);
606 DPRINTF(CxxConfig
, "Connecting probe listeners\n");
607 forEachObject(&SimObject::regProbeListeners
);
611 CxxConfigManager::initState()
613 DPRINTF(CxxConfig
, "Calling initState on all objects\n");
614 forEachObject(&SimObject::initState
);
618 CxxConfigManager::startup()
620 DPRINTF(CxxConfig
, "Starting up all objects\n");
621 forEachObject(&SimObject::startup
);
625 CxxConfigManager::drain()
627 return DrainManager::instance().tryDrain() ? 0 : 1;
631 CxxConfigManager::drainResume()
633 DrainManager::instance().resume();
637 CxxConfigManager::serialize(std::ostream
&os
)
639 for (auto i
= objectsInOrder
.begin(); i
!= objectsInOrder
.end(); ++ i
) {
640 // (*i)->nameOut(os); FIXME, change access spec. for nameOut
641 os
<< '[' << (*i
)->name() << "]\n";
647 CxxConfigManager::loadState(CheckpointIn
&checkpoint
)
649 for (auto i
= objectsInOrder
.begin(); i
!= objectsInOrder
.end(); ++ i
)
650 (*i
)->loadState(checkpoint
);
654 CxxConfigManager::deleteObjects()
656 for (auto i
= objectsInOrder
.rbegin(); i
!= objectsInOrder
.rend(); ++i
) {
657 DPRINTF(CxxConfig
, "Freeing sim object: %s\n", (*i
)->name());
661 for (auto i
= objectParamsByName
.rbegin();
662 i
!= objectParamsByName
.rend(); ++i
)
664 CxxConfigParams
*params
= (*i
).second
;
666 DPRINTF(CxxConfig
, "Freeing sim object params: %s\n",
671 objectsInOrder
.clear();
672 objectsByName
.clear();
676 CxxConfigManager::setParam(const std::string
&object_name
,
677 const std::string
¶m_name
, const std::string
¶m_value
)
679 CxxConfigParams
*params
= findObjectParams(object_name
);
681 if (!params
->setParam(param_name
, param_value
, flags
)) {
682 throw Exception(object_name
, csprintf("Bad parameter value:"
683 " .%s=X=\"%s\"", param_name
, param_value
));
685 std::string instance_name
= rename(object_name
);
687 DPRINTF(CxxConfig
, "Setting parameter %s.%s=%s\n",
688 instance_name
, param_name
, param_value
);
693 CxxConfigManager::setParamVector(const std::string
&object_name
,
694 const std::string
¶m_name
,
695 const std::vector
<std::string
> ¶m_values
)
697 CxxConfigParams
*params
= findObjectParams(object_name
);
699 if (!params
->setParamVector(param_name
, param_values
, flags
)) {
700 throw Exception(object_name
, csprintf("Bad vector parameter value:"
701 " .%s=X=\"%s\"", param_name
, formatParamList(param_values
)));
703 std::string instance_name
= rename(object_name
);
705 DPRINTF(CxxConfig
, "Setting parameter %s.%s=\"%s\"\n",
706 instance_name
, param_name
, formatParamList(param_values
));
710 void CxxConfigManager::addRenaming(const Renaming
&renaming
)
712 renamings
.push_back(renaming
);