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 "mem/mem_object.hh"
49 #include "sim/serialize.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 MemObject
*master_mem_object
= dynamic_cast<MemObject
*>(master_object
);
455 MemObject
*slave_mem_object
= dynamic_cast<MemObject
*>(slave_object
);
457 if (!master_mem_object
) {
458 throw Exception(master_object
->name(), csprintf(
459 "Object isn't a mem object and so can have master port:"
460 " %s[%d]", master_port_name
, master_port_index
));
463 if (!slave_mem_object
) {
464 throw Exception(slave_object
->name(), csprintf(
465 "Object isn't a mem object and so can have slave port:"
466 " %s[%d]", slave_port_name
, slave_port_index
));
469 /* FIXME, check slave_port_index against connection_count
470 * defined for port, need getPortConnectionCount and a
471 * getCxxConfigDirectoryEntry for each object. */
473 /* It would be nice to be able to catch the errors from these calls. */
474 Port
&master_port
= master_mem_object
->getPort(
475 master_port_name
, master_port_index
);
476 Port
&slave_port
= slave_mem_object
->getPort(
477 slave_port_name
, slave_port_index
);
479 if (master_port
.isConnected()) {
480 throw Exception(master_object
->name(), csprintf(
481 "Master port: %s[%d] is already connected\n", master_port_name
,
485 if (slave_port
.isConnected()) {
486 throw Exception(slave_object
->name(), csprintf(
487 "Slave port: %s[%d] is already connected\n", slave_port_name
,
491 DPRINTF(CxxConfig
, "Binding port %s.%s[%d]"
493 master_object
->name(), master_port_name
, master_port_index
,
494 slave_object
->name(), slave_port_name
, slave_port_index
);
496 master_port
.bind(slave_port
);
500 CxxConfigManager::bindMasterPort(SimObject
*object
,
501 const CxxConfigDirectoryEntry::PortDesc
&port
,
502 const std::vector
<std::string
> &peers
)
504 unsigned int master_port_index
= 0;
506 for (auto peer_i
= peers
.begin(); peer_i
!= peers
.end();
509 const std::string
&peer
= *peer_i
;
510 std::string slave_object_name
;
511 std::string slave_port_name
;
512 unsigned int slave_port_index
;
514 parsePort(peer
, slave_object_name
, slave_port_name
,
517 std::string slave_instance_name
= rename(slave_object_name
);
519 if (objectsByName
.find(slave_instance_name
) == objectsByName
.end()) {
520 throw Exception(object
->name(), csprintf(
521 "Can't find slave port object: %s", slave_instance_name
));
524 SimObject
*slave_object
= objectsByName
[slave_instance_name
];
526 bindPort(object
, port
.name
, master_port_index
,
527 slave_object
, slave_port_name
, slave_port_index
);
534 CxxConfigManager::bindObjectPorts(SimObject
*object
)
536 /* We may want to separate object->name() from the name in configuration
537 * later to allow (for example) repetition of fragments of configs */
538 const std::string
&instance_name
= object
->name();
540 std::string object_name
= unRename(instance_name
);
542 std::string object_type
;
543 const CxxConfigDirectoryEntry
&entry
=
544 findObjectType(object_name
, object_type
);
546 DPRINTF(CxxConfig
, "Binding ports of object: %s (%s)\n",
547 instance_name
, object_type
);
549 for (auto i
= entry
.ports
.begin(); i
!= entry
.ports
.end(); ++i
) {
550 const CxxConfigDirectoryEntry::PortDesc
*port
= (*i
).second
;
552 DPRINTF(CxxConfig
, "Binding port: %s.%s\n", instance_name
,
555 std::vector
<std::string
> peers
;
556 configFile
.getPortPeers(object_name
, port
->name
, peers
);
558 /* Only handle master ports as binding only needs to happen once
559 * for each observed pair of ports */
560 if (port
->isMaster
) {
561 if (!port
->isVector
&& peers
.size() > 1) {
562 throw Exception(instance_name
, csprintf(
563 "Too many connections to non-vector port %s (%d)\n",
564 port
->name
, peers
.size()));
567 bindMasterPort(object
, *port
, peers
);
573 CxxConfigManager::parsePort(const std::string
&inp
,
574 std::string
&path
, std::string
&port
, unsigned int &index
)
576 std::size_t dot_i
= inp
.rfind('.');
577 std::size_t open_square_i
= inp
.rfind('[');
579 if (dot_i
== std::string::npos
) {
580 DPRINTF(CxxConfig
, "Bad port string: %s\n", inp
);
585 path
= std::string(inp
, 0, dot_i
);
587 if (open_square_i
== std::string::npos
) {
589 port
= std::string(inp
, dot_i
+ 1, inp
.length() - dot_i
);
592 /* Vectored port elemnt */
593 port
= std::string(inp
, dot_i
+ 1, (open_square_i
- 1) - dot_i
);
594 index
= std::atoi(inp
.c_str() + open_square_i
+ 1);
600 CxxConfigManager::forEachObject(void (SimObject::*mem_func
)())
602 for (auto i
= objectsInOrder
.begin(); i
!= objectsInOrder
.end(); ++i
)
607 CxxConfigManager::instantiate(bool build_all
)
614 DPRINTF(CxxConfig
, "Initialising all objects\n");
615 forEachObject(&SimObject::init
);
617 DPRINTF(CxxConfig
, "Registering stats\n");
618 forEachObject(&SimObject::regStats
);
620 DPRINTF(CxxConfig
, "Registering probe points\n");
621 forEachObject(&SimObject::regProbePoints
);
623 DPRINTF(CxxConfig
, "Connecting probe listeners\n");
624 forEachObject(&SimObject::regProbeListeners
);
628 CxxConfigManager::initState()
630 DPRINTF(CxxConfig
, "Calling initState on all objects\n");
631 forEachObject(&SimObject::initState
);
635 CxxConfigManager::startup()
637 DPRINTF(CxxConfig
, "Starting up all objects\n");
638 forEachObject(&SimObject::startup
);
642 CxxConfigManager::drain()
644 return DrainManager::instance().tryDrain() ? 0 : 1;
648 CxxConfigManager::drainResume()
650 DrainManager::instance().resume();
654 CxxConfigManager::serialize(std::ostream
&os
)
656 for (auto i
= objectsInOrder
.begin(); i
!= objectsInOrder
.end(); ++ i
) {
657 // (*i)->nameOut(os); FIXME, change access spec. for nameOut
658 os
<< '[' << (*i
)->name() << "]\n";
664 CxxConfigManager::loadState(CheckpointIn
&checkpoint
)
666 for (auto i
= objectsInOrder
.begin(); i
!= objectsInOrder
.end(); ++ i
)
667 (*i
)->loadState(checkpoint
);
671 CxxConfigManager::deleteObjects()
673 for (auto i
= objectsInOrder
.rbegin(); i
!= objectsInOrder
.rend(); ++i
) {
674 DPRINTF(CxxConfig
, "Freeing sim object: %s\n", (*i
)->name());
678 for (auto i
= objectParamsByName
.rbegin();
679 i
!= objectParamsByName
.rend(); ++i
)
681 CxxConfigParams
*params
= (*i
).second
;
683 DPRINTF(CxxConfig
, "Freeing sim object params: %s\n",
688 objectsInOrder
.clear();
689 objectsByName
.clear();
693 CxxConfigManager::setParam(const std::string
&object_name
,
694 const std::string
¶m_name
, const std::string
¶m_value
)
696 CxxConfigParams
*params
= findObjectParams(object_name
);
698 if (!params
->setParam(param_name
, param_value
, flags
)) {
699 throw Exception(object_name
, csprintf("Bad parameter value:"
700 " .%s=X=\"%s\"", param_name
, param_value
));
702 std::string instance_name
= rename(object_name
);
704 DPRINTF(CxxConfig
, "Setting parameter %s.%s=%s\n",
705 instance_name
, param_name
, param_value
);
710 CxxConfigManager::setParamVector(const std::string
&object_name
,
711 const std::string
¶m_name
,
712 const std::vector
<std::string
> ¶m_values
)
714 CxxConfigParams
*params
= findObjectParams(object_name
);
716 if (!params
->setParamVector(param_name
, param_values
, flags
)) {
717 throw Exception(object_name
, csprintf("Bad vector parameter value:"
718 " .%s=X=\"%s\"", param_name
, formatParamList(param_values
)));
720 std::string instance_name
= rename(object_name
);
722 DPRINTF(CxxConfig
, "Setting parameter %s.%s=\"%s\"\n",
723 instance_name
, param_name
, formatParamList(param_values
));
727 void CxxConfigManager::addRenaming(const Renaming
&renaming
)
729 renamings
.push_back(renaming
);