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
40 #include "sim/cxx_manager.hh"
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"
51 CxxConfigManager::CxxConfigManager(CxxConfigFileBase
&configFile_
) :
52 configFile(configFile_
), flags(configFile_
.getFlags()),
53 simObjectResolver(*this)
57 const CxxConfigDirectoryEntry
&
58 CxxConfigManager::findObjectType(const std::string
&object_name
,
59 std::string
&object_type
)
61 if (!configFile
.objectExists(object_name
))
62 throw Exception(object_name
, "Can't find sim object");
64 if (!configFile
.getParam(object_name
, "type", object_type
))
65 throw Exception(object_name
, "Sim object has no 'type' field");
67 if (cxx_config_directory
.find(object_type
) ==
68 cxx_config_directory
.end())
70 throw Exception(object_name
, csprintf(
71 "No sim object type %s is available", object_type
));
74 const CxxConfigDirectoryEntry
*entry
= cxx_config_directory
[object_type
];
80 CxxConfigManager::rename(const std::string
&from_name
)
82 for (auto i
= renamings
.begin(); i
!= renamings
.end(); ++ i
) {
83 const Renaming
&renaming
= *i
;
85 if (from_name
.find(renaming
.fromPrefix
) == 0) {
86 return renaming
.toPrefix
+
87 from_name
.substr(renaming
.fromPrefix
.length());
95 CxxConfigManager::unRename(const std::string
&to_name
)
97 for (auto i
= renamings
.begin(); i
!= renamings
.end(); ++ i
) {
98 const Renaming
&renaming
= *i
;
100 if (to_name
.find(renaming
.toPrefix
) == 0) {
101 return renaming
.fromPrefix
+
102 to_name
.substr(renaming
.toPrefix
.length());
110 std::string
formatParamList(const std::vector
<std::string
> ¶m_values
)
112 std::ostringstream params
;
114 auto i
= param_values
.begin();
115 auto end_i
= param_values
.end();
131 CxxConfigManager::findObject(const std::string
&object_name
,
134 std::string instance_name
= rename(object_name
);
136 if (object_name
== "Null")
139 /* Already constructed */
140 if (objectsByName
.find(instance_name
) != objectsByName
.end())
141 return objectsByName
[instance_name
];
143 if (inVisit
.find(instance_name
) != inVisit
.end())
144 throw Exception(instance_name
, "Cycle in configuration");
146 std::string object_type
;
147 const CxxConfigDirectoryEntry
&entry
=
148 findObjectType(object_name
, object_type
);
150 SimObject
*object
= NULL
;
152 CxxConfigParams
*object_params
= findObjectParams(object_name
);
155 DPRINTF(CxxConfig
, "Configuring sim object references for: %s"
156 " (%s from object %s)\n", instance_name
, object_type
,
159 /* Remember the path back to the top of the recursion to detect
161 inVisit
.insert(instance_name
);
163 /* Resolve pointed-to SimObjects by recursing into them */
164 for (auto i
= entry
.parameters
.begin();
165 i
!= entry
.parameters
.end(); ++i
)
167 const CxxConfigDirectoryEntry::ParamDesc
*param
= (*i
).second
;
169 if (param
->isSimObject
) {
170 if (param
->isVector
) {
171 std::vector
<std::string
> sub_object_names
;
173 if (!configFile
.getParamVector(object_name
, param
->name
,
176 throw Exception(object_name
, csprintf(
177 "Element not found: %s", param
->name
));
180 std::vector
<SimObject
*> sub_objects
;
182 for (auto n
= sub_object_names
.begin();
183 n
!= sub_object_names
.end(); ++n
)
185 SimObject
*sub_object
= findObject(*n
,
189 sub_objects
.push_back(sub_object
);
192 if (!object_params
->setSimObjectVector(param
->name
,
195 throw Exception(object_name
, csprintf(
196 "Can't assign sim object element %s from \"%s\"",
197 param
->name
, formatParamList(sub_object_names
)));
200 DPRINTF(CxxConfig
, "Setting sim object(s): %s.%s=%s\n",
201 object_name
, param
->name
,
202 formatParamList(sub_object_names
));
204 std::string sub_object_name
;
206 if (!configFile
.getParam(object_name
, param
->name
,
209 throw Exception(object_name
, csprintf(
210 "Element not found: %s", param
->name
));
213 SimObject
*sub_object
= findObject(sub_object_name
,
217 if (!object_params
->setSimObject(param
->name
,
220 throw Exception(object_name
, csprintf(
221 "Can't assign sim object element %s from"
222 " \"%s\"", param
->name
, sub_object_name
));
226 DPRINTF(CxxConfig
, "Setting sim object(s):"
227 " %s.%s=%s\n", object_name
, param
->name
,
233 DPRINTF(CxxConfig
, "Creating SimObject: %s\n", instance_name
);
234 object
= object_params
->simObjectCreate();
237 throw Exception(object_name
, csprintf("Couldn't create object of"
238 " type: %s", object_type
));
241 objectsByName
[instance_name
] = object
;
242 objectParamsByName
[instance_name
] = object_params
;
244 if (visit_children
) {
245 std::vector
<std::string
> children
;
246 configFile
.getObjectChildren(object_name
, children
, true);
248 /* Visit all your children */
249 for (auto i
= children
.begin(); i
!= children
.end(); ++i
)
250 findObject(*i
, visit_children
);
252 } catch (Exception
&) {
253 delete object_params
;
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
);
265 CxxConfigManager::findObjectParams(const std::string
&object_name
)
267 std::string instance_name
= rename(object_name
);
269 /* Already constructed */
270 if (objectParamsByName
.find(instance_name
) != objectParamsByName
.end())
271 return objectParamsByName
[instance_name
];
273 std::string object_type
;
274 const CxxConfigDirectoryEntry
&entry
=
275 findObjectType(object_name
, object_type
);
277 DPRINTF(CxxConfig
, "Configuring parameters of object: %s (%s)\n",
278 instance_name
, object_type
);
280 CxxConfigParams
*object_params
= entry
.makeParamsObject();
283 /* Fill in the implicit parameters that don't necessarily
284 * appear in config files */
285 object_params
->setName(instance_name
);
287 /* Fill in parameters */
288 for (auto i
= entry
.parameters
.begin();
289 i
!= entry
.parameters
.end(); ++i
)
291 const CxxConfigDirectoryEntry::ParamDesc
*param
= (*i
).second
;
293 if (!param
->isSimObject
) {
294 /* Only handle non-SimObject parameters here (see below) */
296 if (param
->isVector
) {
297 std::vector
<std::string
> param_values
;
299 if (!configFile
.getParamVector(object_name
, param
->name
,
302 throw Exception(object_name
, csprintf(
303 "Element not found for parameter: %s",
307 if (!object_params
->setParamVector(param
->name
,
308 param_values
, flags
))
310 throw Exception(instance_name
, csprintf(
311 "Bad parameter value: .%s=X=\"%s\"",
312 param
->name
, formatParamList(param_values
)));
315 DPRINTF(CxxConfig
, "Setting parameter"
316 " %s.%s=%s\n", instance_name
, param
->name
,
317 formatParamList(param_values
));
319 std::string param_value
;
321 if (!configFile
.getParam(object_name
, param
->name
,
324 throw Exception(object_name
, csprintf(
325 "Element not found for parameter: %s",
329 if (!object_params
->setParam(param
->name
, param_value
,
332 throw Exception(instance_name
, csprintf(
333 "Bad parameter value: .%s=X=\"%s\"",
334 param
->name
, param_value
));
337 DPRINTF(CxxConfig
, "Setting parameter %s.%s=%s\n",
338 instance_name
, param
->name
, param_value
);
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
;
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
);
355 unsigned int peer_count
= peers
.size();
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 */
362 if (!object_params
->setPortConnectionCount(port
->name
,
365 throw Exception(instance_name
, csprintf(
366 "Unconnected port: %s", port
->name
));
369 DPRINTF(CxxConfig
, "Setting port connection count"
370 " for: %s.%s to %d\n",
371 instance_name
, port
->name
, peer_count
);
374 /* Set pointed-to SimObjects to NULL */
375 for (auto i
= entry
.parameters
.begin();
376 i
!= entry
.parameters
.end(); ++i
)
378 const CxxConfigDirectoryEntry::ParamDesc
*param
= (*i
).second
;
380 if (param
->isSimObject
) {
383 DPRINTF(CxxConfig
, "Nulling sim object reference: %s.%s\n",
384 instance_name
, param
->name
);
386 if (param
->isVector
) {
387 /* Clear the reference list. */
388 std::vector
<SimObject
*> empty
;
389 ret
= object_params
->setSimObjectVector(param
->name
,
392 ret
= object_params
->setSimObject(param
->name
, NULL
);
396 throw Exception(instance_name
, csprintf(
397 "Error nulling sim object reference(s): %s",
402 } catch (Exception
&) {
403 delete object_params
;
407 objectParamsByName
[instance_name
] = object_params
;
409 return object_params
;
413 CxxConfigManager::findAllObjects()
415 std::vector
<std::string
> objects
;
416 configFile
.getAllObjectNames(objects
);
418 /* Set the traversal order for further iterators */
419 objectsInOrder
.clear();
420 findTraversalOrder("root");
424 CxxConfigManager::findTraversalOrder(const std::string
&object_name
)
426 SimObject
*object
= findObject(object_name
);
429 objectsInOrder
.push_back(object
);
431 std::vector
<std::string
> children
;
432 configFile
.getObjectChildren(object_name
, children
, true);
434 /* Visit all your children */
435 for (auto i
= children
.begin(); i
!= children
.end(); ++i
)
436 findTraversalOrder(*i
);
441 CxxConfigManager::bindAllPorts()
443 for (auto i
= objectsInOrder
.begin(); i
!= objectsInOrder
.end(); ++i
)
448 CxxConfigManager::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
)
454 /* FIXME, check slave_port_index against connection_count
455 * defined for port, need getPortConnectionCount and a
456 * getCxxConfigDirectoryEntry for each object. */
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
);
464 if (master_port
.isConnected()) {
465 throw Exception(master_object
->name(), csprintf(
466 "Master port: %s[%d] is already connected\n", master_port_name
,
470 if (slave_port
.isConnected()) {
471 throw Exception(slave_object
->name(), csprintf(
472 "Slave port: %s[%d] is already connected\n", slave_port_name
,
476 DPRINTF(CxxConfig
, "Binding port %s.%s[%d]"
478 master_object
->name(), master_port_name
, master_port_index
,
479 slave_object
->name(), slave_port_name
, slave_port_index
);
481 master_port
.bind(slave_port
);
485 CxxConfigManager::bindMasterPort(SimObject
*object
,
486 const CxxConfigDirectoryEntry::PortDesc
&port
,
487 const std::vector
<std::string
> &peers
)
489 unsigned int master_port_index
= 0;
491 for (auto peer_i
= peers
.begin(); peer_i
!= peers
.end();
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
;
499 parsePort(peer
, slave_object_name
, slave_port_name
,
502 std::string slave_instance_name
= rename(slave_object_name
);
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
));
509 SimObject
*slave_object
= objectsByName
[slave_instance_name
];
511 bindPort(object
, port
.name
, master_port_index
,
512 slave_object
, slave_port_name
, slave_port_index
);
519 CxxConfigManager::bindObjectPorts(SimObject
*object
)
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();
525 std::string object_name
= unRename(instance_name
);
527 std::string object_type
;
528 const CxxConfigDirectoryEntry
&entry
=
529 findObjectType(object_name
, object_type
);
531 DPRINTF(CxxConfig
, "Binding ports of object: %s (%s)\n",
532 instance_name
, object_type
);
534 for (auto i
= entry
.ports
.begin(); i
!= entry
.ports
.end(); ++i
) {
535 const CxxConfigDirectoryEntry::PortDesc
*port
= (*i
).second
;
537 DPRINTF(CxxConfig
, "Binding port: %s.%s\n", instance_name
,
540 std::vector
<std::string
> peers
;
541 configFile
.getPortPeers(object_name
, port
->name
, peers
);
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()));
552 bindMasterPort(object
, *port
, peers
);
558 CxxConfigManager::parsePort(const std::string
&inp
,
559 std::string
&path
, std::string
&port
, unsigned int &index
)
561 std::size_t dot_i
= inp
.rfind('.');
562 std::size_t open_square_i
= inp
.rfind('[');
564 if (dot_i
== std::string::npos
) {
565 DPRINTF(CxxConfig
, "Bad port string: %s\n", inp
);
570 path
= std::string(inp
, 0, dot_i
);
572 if (open_square_i
== std::string::npos
) {
574 port
= std::string(inp
, dot_i
+ 1, inp
.length() - dot_i
);
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);
585 CxxConfigManager::forEachObject(void (SimObject::*mem_func
)())
587 for (auto i
= objectsInOrder
.begin(); i
!= objectsInOrder
.end(); ++i
)
592 CxxConfigManager::instantiate(bool build_all
)
599 DPRINTF(CxxConfig
, "Initialising all objects\n");
600 forEachObject(&SimObject::init
);
602 DPRINTF(CxxConfig
, "Registering stats\n");
603 forEachObject(&SimObject::regStats
);
605 DPRINTF(CxxConfig
, "Registering probe points\n");
606 forEachObject(&SimObject::regProbePoints
);
608 DPRINTF(CxxConfig
, "Connecting probe listeners\n");
609 forEachObject(&SimObject::regProbeListeners
);
613 CxxConfigManager::initState()
615 DPRINTF(CxxConfig
, "Calling initState on all objects\n");
616 forEachObject(&SimObject::initState
);
620 CxxConfigManager::startup()
622 DPRINTF(CxxConfig
, "Starting up all objects\n");
623 forEachObject(&SimObject::startup
);
627 CxxConfigManager::drain()
629 return DrainManager::instance().tryDrain() ? 0 : 1;
633 CxxConfigManager::drainResume()
635 DrainManager::instance().resume();
639 CxxConfigManager::serialize(std::ostream
&os
)
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";
649 CxxConfigManager::loadState(CheckpointIn
&checkpoint
)
651 for (auto i
= objectsInOrder
.begin(); i
!= objectsInOrder
.end(); ++ i
)
652 (*i
)->loadState(checkpoint
);
656 CxxConfigManager::deleteObjects()
658 for (auto i
= objectsInOrder
.rbegin(); i
!= objectsInOrder
.rend(); ++i
) {
659 DPRINTF(CxxConfig
, "Freeing sim object: %s\n", (*i
)->name());
663 for (auto i
= objectParamsByName
.rbegin();
664 i
!= objectParamsByName
.rend(); ++i
)
666 CxxConfigParams
*params
= (*i
).second
;
668 DPRINTF(CxxConfig
, "Freeing sim object params: %s\n",
673 objectsInOrder
.clear();
674 objectsByName
.clear();
678 CxxConfigManager::setParam(const std::string
&object_name
,
679 const std::string
¶m_name
, const std::string
¶m_value
)
681 CxxConfigParams
*params
= findObjectParams(object_name
);
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
));
687 std::string instance_name
= rename(object_name
);
689 DPRINTF(CxxConfig
, "Setting parameter %s.%s=%s\n",
690 instance_name
, param_name
, param_value
);
695 CxxConfigManager::setParamVector(const std::string
&object_name
,
696 const std::string
¶m_name
,
697 const std::vector
<std::string
> ¶m_values
)
699 CxxConfigParams
*params
= findObjectParams(object_name
);
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
)));
705 std::string instance_name
= rename(object_name
);
707 DPRINTF(CxxConfig
, "Setting parameter %s.%s=\"%s\"\n",
708 instance_name
, param_name
, formatParamList(param_values
));
712 void CxxConfigManager::addRenaming(const Renaming
&renaming
)
714 renamings
.push_back(renaming
);