cxx_manager.cc (11793:ef606668d247) cxx_manager.cc (11800:54436a1784dc)
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"
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"
46#include "debug/CxxConfig.hh"
47#include "mem/mem_object.hh"
48#include "sim/serialize.hh"
49
50CxxConfigManager::CxxConfigManager(CxxConfigFileBase &configFile_) :
51 configFile(configFile_), flags(configFile_.getFlags()),
52 simObjectResolver(*this)
53{
54}
55
56const CxxConfigDirectoryEntry &
57CxxConfigManager::findObjectType(const std::string &object_name,
58 std::string &object_type)
59{
60 if (!configFile.objectExists(object_name))
61 throw Exception(object_name, "Can't find sim object");
62
63 if (!configFile.getParam(object_name, "type", object_type))
64 throw Exception(object_name, "Sim object has no 'type' field");
65
66 if (cxx_config_directory.find(object_type) ==
67 cxx_config_directory.end())
68 {
69 throw Exception(object_name, csprintf(
70 "No sim object type %s is available", object_type));
71 }
72
73 const CxxConfigDirectoryEntry *entry = cxx_config_directory[object_type];
74
75 return *entry;
76}
77
78std::string
79CxxConfigManager::rename(const std::string &from_name)
80{
81 for (auto i = renamings.begin(); i != renamings.end(); ++ i) {
82 const Renaming &renaming = *i;
83
84 if (from_name.find(renaming.fromPrefix) == 0) {
85 return renaming.toPrefix +
86 from_name.substr(renaming.fromPrefix.length());
87 }
88 }
89
90 return from_name;
91}
92
93std::string
94CxxConfigManager::unRename(const std::string &to_name)
95{
96 for (auto i = renamings.begin(); i != renamings.end(); ++ i) {
97 const Renaming &renaming = *i;
98
99 if (to_name.find(renaming.toPrefix) == 0) {
100 return renaming.fromPrefix +
101 to_name.substr(renaming.toPrefix.length());
102 }
103 }
104
105 return to_name;
106}
107
108static
109std::string formatParamList(const std::vector<std::string> &param_values)
110{
111 std::ostringstream params;
112
113 auto i = param_values.begin();
114 auto end_i = param_values.end();
115
116 params << '[';
117 while (i != end_i) {
118 params << (*i);
119 ++i;
120
121 if (i != end_i)
122 params << ", ";
123 }
124 params << ']';
125
126 return params.str();
127}
128
129SimObject *
130CxxConfigManager::findObject(const std::string &object_name,
131 bool visit_children)
132{
133 std::string instance_name = rename(object_name);
134
135 if (object_name == "Null")
136 return NULL;
137
138 /* Already constructed */
139 if (objectsByName.find(instance_name) != objectsByName.end())
140 return objectsByName[instance_name];
141
142 if (inVisit.find(instance_name) != inVisit.end())
143 throw Exception(instance_name, "Cycle in configuration");
144
145 std::string object_type;
146 const CxxConfigDirectoryEntry &entry =
147 findObjectType(object_name, object_type);
148
149 SimObject *object = NULL;
150
151 CxxConfigParams *object_params = findObjectParams(object_name);
152
153 try {
154 DPRINTF(CxxConfig, "Configuring sim object references for: %s"
155 " (%s from object %s)\n", instance_name, object_type,
156 object_name);
157
158 /* Remember the path back to the top of the recursion to detect
159 * cycles */
160 inVisit.insert(instance_name);
161
162 /* Resolve pointed-to SimObjects by recursing into them */
163 for (auto i = entry.parameters.begin();
164 i != entry.parameters.end(); ++i)
165 {
166 const CxxConfigDirectoryEntry::ParamDesc *param = (*i).second;
167
168 if (param->isSimObject) {
169 if (param->isVector) {
170 std::vector<std::string> sub_object_names;
171
172 if (!configFile.getParamVector(object_name, param->name,
173 sub_object_names))
174 {
175 throw Exception(object_name, csprintf(
176 "Element not found: %s", param->name));
177 }
178
179 std::vector<SimObject *> sub_objects;
180
181 for (auto n = sub_object_names.begin();
182 n != sub_object_names.end(); ++n)
183 {
184 SimObject *sub_object = findObject(*n,
185 visit_children);
186
187 if (sub_object)
188 sub_objects.push_back(sub_object);
189 }
190
191 if (!object_params->setSimObjectVector(param->name,
192 sub_objects))
193 {
194 throw Exception(object_name, csprintf(
195 "Can't assign sim object element %s from \"%s\"",
196 param->name, formatParamList(sub_object_names)));
197 }
198
199 DPRINTF(CxxConfig, "Setting sim object(s): %s.%s=%s\n",
200 object_name, param->name,
201 formatParamList(sub_object_names));
202 } else {
203 std::string sub_object_name;
204
205 if (!configFile.getParam(object_name, param->name,
206 sub_object_name))
207 {
208 throw Exception(object_name, csprintf(
209 "Element not found: %s", param->name));
210 }
211
212 SimObject *sub_object = findObject(sub_object_name,
213 visit_children);
214
215 if (sub_object) {
216 if (!object_params->setSimObject(param->name,
217 sub_object))
218 {
219 throw Exception(object_name, csprintf(
220 "Can't assign sim object element %s from"
221 " \"%s\"", param->name, sub_object_name));
222 }
223 }
224
225 DPRINTF(CxxConfig, "Setting sim object(s):"
226 " %s.%s=%s\n", object_name, param->name,
227 sub_object_name);
228 }
229 }
230 }
231
232 DPRINTF(CxxConfig, "Creating SimObject: %s\n", instance_name);
233 object = object_params->simObjectCreate();
234
235 if (!object) {
236 throw Exception(object_name, csprintf("Couldn't create object of"
237 " type: %s", object_type));
238 }
239
240 objectsByName[instance_name] = object;
241 objectParamsByName[instance_name] = object_params;
242
243 if (visit_children) {
244 std::vector<std::string> children;
245 configFile.getObjectChildren(object_name, children, true);
246
247 /* Visit all your children */
248 for (auto i = children.begin(); i != children.end(); ++i)
249 findObject(*i, visit_children);
250 }
251 } catch (Exception &) {
252 delete object_params;
253 throw;
254 }
255
256 /* Mark that we've exited object
257 * construction and so 'find'ing this object again won't be a
258 * configuration loop */
259 inVisit.erase(object_name);
260 return object;
261}
262
263CxxConfigParams *
264CxxConfigManager::findObjectParams(const std::string &object_name)
265{
266 std::string instance_name = rename(object_name);
267
268 /* Already constructed */
269 if (objectParamsByName.find(instance_name) != objectParamsByName.end())
270 return objectParamsByName[instance_name];
271
272 std::string object_type;
273 const CxxConfigDirectoryEntry &entry =
274 findObjectType(object_name, object_type);
275
276 DPRINTF(CxxConfig, "Configuring parameters of object: %s (%s)\n",
277 instance_name, object_type);
278
279 CxxConfigParams *object_params = entry.makeParamsObject();
280
281 try {
282 /* Fill in the implicit parameters that don't necessarily
283 * appear in config files */
284 object_params->setName(instance_name);
285
286 /* Fill in parameters */
287 for (auto i = entry.parameters.begin();
288 i != entry.parameters.end(); ++i)
289 {
290 const CxxConfigDirectoryEntry::ParamDesc *param = (*i).second;
291
292 if (!param->isSimObject) {
293 /* Only handle non-SimObject parameters here (see below) */
294
295 if (param->isVector) {
296 std::vector<std::string> param_values;
297
298 if (!configFile.getParamVector(object_name, param->name,
299 param_values))
300 {
301 throw Exception(object_name, csprintf(
302 "Element not found for parameter: %s",
303 param->name));
304 }
305
306 if (!object_params->setParamVector(param->name,
307 param_values, flags))
308 {
309 throw Exception(instance_name, csprintf(
310 "Bad parameter value: .%s=X=\"%s\"",
311 param->name, formatParamList(param_values)));
312 }
313
314 DPRINTF(CxxConfig, "Setting parameter"
315 " %s.%s=%s\n", instance_name, param->name,
316 formatParamList(param_values));
317 } else {
318 std::string param_value;
319
320 if (!configFile.getParam(object_name, param->name,
321 param_value))
322 {
323 throw Exception(object_name, csprintf(
324 "Element not found for parameter: %s",
325 param->name));
326 }
327
328 if (!object_params->setParam(param->name, param_value,
329 flags))
330 {
331 throw Exception(instance_name, csprintf(
332 "Bad parameter value: .%s=X=\"%s\"",
333 param->name, param_value));
334 }
335
336 DPRINTF(CxxConfig, "Setting parameter %s.%s=%s\n",
337 instance_name, param->name, param_value);
338 }
339 }
340 }
341
342 /* Find the number of ports that will need binding and set the
343 * appropriate port_..._connection_count parameters */
344 for (auto i = entry.ports.begin(); i != entry.ports.end(); ++i) {
345 const CxxConfigDirectoryEntry::PortDesc *port = (*i).second;
346 std::vector<std::string> peers;
347
348 if (!configFile.getPortPeers(object_name, port->name, peers)) {
349 DPRINTF(CxxConfig, "Port not found: %s.%s,"
350 " assuming there are no connections\n",
351 instance_name, port->name);
352 }
353
354 unsigned int peer_count = peers.size();
355
356 /* It would be more efficient to split the peer list and
357 * save the values for peer binding later but that would
358 * require another annoying intermediate structure to
359 * hold for little performance increase */
360
361 if (!object_params->setPortConnectionCount(port->name,
362 peer_count))
363 {
364 throw Exception(instance_name, csprintf(
365 "Unconnected port: %s", port->name));
366 }
367
368 DPRINTF(CxxConfig, "Setting port connection count"
369 " for: %s.%s to %d\n",
370 instance_name, port->name, peer_count);
371 }
372
373 /* Set pointed-to SimObjects to NULL */
374 for (auto i = entry.parameters.begin();
375 i != entry.parameters.end(); ++i)
376 {
377 const CxxConfigDirectoryEntry::ParamDesc *param = (*i).second;
378
379 if (param->isSimObject) {
380 bool ret;
381
382 DPRINTF(CxxConfig, "Nulling sim object reference: %s.%s\n",
383 instance_name, param->name);
384
385 if (param->isVector) {
386 /* Clear the reference list. */
387 std::vector<SimObject *> empty;
388 ret = object_params->setSimObjectVector(param->name,
389 empty);
390 } else {
391 ret = object_params->setSimObject(param->name, NULL);
392 }
393
394 if (!ret) {
395 throw Exception(instance_name, csprintf(
396 "Error nulling sim object reference(s): %s",
397 param->name));
398 }
399 }
400 }
401 } catch (Exception &) {
402 delete object_params;
403 throw;
404 }
405
406 objectParamsByName[instance_name] = object_params;
407
408 return object_params;
409}
410
411void
412CxxConfigManager::findAllObjects()
413{
414 std::vector<std::string> objects;
415 configFile.getAllObjectNames(objects);
416
417 /* Sort the object names to get a consistent initialisation order
418 * even with config file reorganisation */
419 std::sort(objects.begin(), objects.end());
420
421 for (auto i = objects.begin(); i != objects.end(); ++i)
422 findObject(*i);
423
424 /* Set the traversal order for further iterators */
425 objectsInOrder.clear();
426 findTraversalOrder("root");
427}
428
429void
430CxxConfigManager::findTraversalOrder(const std::string &object_name)
431{
432 SimObject *object = findObject(object_name);
433
434 if (object) {
435 objectsInOrder.push_back(object);
436
437 std::vector<std::string> children;
438 configFile.getObjectChildren(object_name, children, true);
439
440 /* Visit all your children */
441 for (auto i = children.begin(); i != children.end(); ++i)
442 findTraversalOrder(*i);
443 }
444}
445
446void
447CxxConfigManager::bindAllPorts()
448{
449 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++i)
450 bindObjectPorts(*i);
451}
452
453void
454CxxConfigManager::bindPort(
455 SimObject *master_object, const std::string &master_port_name,
456 PortID master_port_index,
457 SimObject *slave_object, const std::string &slave_port_name,
458 PortID slave_port_index)
459{
460 MemObject *master_mem_object = dynamic_cast<MemObject *>(master_object);
461 MemObject *slave_mem_object = dynamic_cast<MemObject *>(slave_object);
462
463 if (!master_mem_object) {
464 throw Exception(master_object->name(), csprintf(
465 "Object isn't a mem object and so can have master port:"
466 " %s[%d]", master_port_name, master_port_index));
467 }
468
469 if (!slave_mem_object) {
470 throw Exception(slave_object->name(), csprintf(
471 "Object isn't a mem object and so can have slave port:"
472 " %s[%d]", slave_port_name, slave_port_index));
473 }
474
475 /* FIXME, check slave_port_index against connection_count
476 * defined for port, need getPortConnectionCount and a
477 * getCxxConfigDirectoryEntry for each object. */
478
479 /* It would be nice to be able to catch the errors from these calls. */
480 BaseMasterPort &master_port = master_mem_object->getMasterPort(
481 master_port_name, master_port_index);
482 BaseSlavePort &slave_port = slave_mem_object->getSlavePort(
483 slave_port_name, slave_port_index);
484
485 if (master_port.isConnected()) {
486 throw Exception(master_object->name(), csprintf(
487 "Master port: %s[%d] is already connected\n", master_port_name,
488 master_port_index));
489 }
490
491 if (slave_port.isConnected()) {
492 throw Exception(slave_object->name(), csprintf(
493 "Slave port: %s[%d] is already connected\n", slave_port_name,
494 slave_port_index));
495 }
496
497 DPRINTF(CxxConfig, "Binding port %s.%s[%d]"
498 " to %s:%s[%d]\n",
499 master_object->name(), master_port_name, master_port_index,
500 slave_object->name(), slave_port_name, slave_port_index);
501
502 master_port.bind(slave_port);
503}
504
505void
506CxxConfigManager::bindMasterPort(SimObject *object,
507 const CxxConfigDirectoryEntry::PortDesc &port,
508 const std::vector<std::string> &peers)
509{
510 unsigned int master_port_index = 0;
511
512 for (auto peer_i = peers.begin(); peer_i != peers.end();
513 ++peer_i)
514 {
515 const std::string &peer = *peer_i;
516 std::string slave_object_name;
517 std::string slave_port_name;
518 unsigned int slave_port_index;
519
520 parsePort(peer, slave_object_name, slave_port_name,
521 slave_port_index);
522
523 std::string slave_instance_name = rename(slave_object_name);
524
525 if (objectsByName.find(slave_instance_name) == objectsByName.end()) {
526 throw Exception(object->name(), csprintf(
527 "Can't find slave port object: %s", slave_instance_name));
528 }
529
530 SimObject *slave_object = objectsByName[slave_instance_name];
531
532 bindPort(object, port.name, master_port_index,
533 slave_object, slave_port_name, slave_port_index);
534
535 master_port_index++;
536 }
537}
538
539void
540CxxConfigManager::bindObjectPorts(SimObject *object)
541{
542 /* We may want to separate object->name() from the name in configuration
543 * later to allow (for example) repetition of fragments of configs */
544 const std::string &instance_name = object->name();
545
546 std::string object_name = unRename(instance_name);
547
548 std::string object_type;
549 const CxxConfigDirectoryEntry &entry =
550 findObjectType(object_name, object_type);
551
552 DPRINTF(CxxConfig, "Binding ports of object: %s (%s)\n",
553 instance_name, object_type);
554
555 for (auto i = entry.ports.begin(); i != entry.ports.end(); ++i) {
556 const CxxConfigDirectoryEntry::PortDesc *port = (*i).second;
557
558 DPRINTF(CxxConfig, "Binding port: %s.%s\n", instance_name,
559 port->name);
560
561 std::vector<std::string> peers;
562 configFile.getPortPeers(object_name, port->name, peers);
563
564 /* Only handle master ports as binding only needs to happen once
565 * for each observed pair of ports */
566 if (port->isMaster) {
567 if (!port->isVector && peers.size() > 1) {
568 throw Exception(instance_name, csprintf(
569 "Too many connections to non-vector port %s (%d)\n",
570 port->name, peers.size()));
571 }
572
573 bindMasterPort(object, *port, peers);
574 }
575 }
576}
577
578void
579CxxConfigManager::parsePort(const std::string &inp,
580 std::string &path, std::string &port, unsigned int &index)
581{
582 std::size_t dot_i = inp.rfind('.');
583 std::size_t open_square_i = inp.rfind('[');
584
585 if (dot_i == std::string::npos) {
586 DPRINTF(CxxConfig, "Bad port string: %s\n", inp);
587 path = "";
588 port = "";
589 index = 0;
590 } else {
591 path = std::string(inp, 0, dot_i);
592
593 if (open_square_i == std::string::npos) {
594 /* Singleton port */
595 port = std::string(inp, dot_i + 1, inp.length() - dot_i);
596 index = 0;
597 } else {
598 /* Vectored port elemnt */
599 port = std::string(inp, dot_i + 1, (open_square_i - 1) - dot_i);
600 index = std::atoi(inp.c_str() + open_square_i + 1);
601 }
602 }
603}
604
605void
606CxxConfigManager::forEachObject(void (SimObject::*mem_func)())
607{
608 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++i)
609 ((*i)->*mem_func)();
610}
611
612void
613CxxConfigManager::instantiate(bool build_all)
614{
615 if (build_all) {
616 findAllObjects();
617 bindAllPorts();
618 }
619
620 DPRINTF(CxxConfig, "Initialising all objects\n");
621 forEachObject(&SimObject::init);
622
623 DPRINTF(CxxConfig, "Registering stats\n");
624 forEachObject(&SimObject::regStats);
625
626 DPRINTF(CxxConfig, "Registering probe points\n");
627 forEachObject(&SimObject::regProbePoints);
628
629 DPRINTF(CxxConfig, "Connecting probe listeners\n");
630 forEachObject(&SimObject::regProbeListeners);
631}
632
633void
634CxxConfigManager::initState()
635{
636 DPRINTF(CxxConfig, "Calling initState on all objects\n");
637 forEachObject(&SimObject::initState);
638}
639
640void
641CxxConfigManager::startup()
642{
643 DPRINTF(CxxConfig, "Starting up all objects\n");
644 forEachObject(&SimObject::startup);
645}
646
647unsigned int
648CxxConfigManager::drain()
649{
650 return DrainManager::instance().tryDrain() ? 0 : 1;
651}
652
653void
654CxxConfigManager::drainResume()
655{
656 DrainManager::instance().resume();
657}
658
659void
660CxxConfigManager::serialize(std::ostream &os)
661{
662 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++ i) {
663 // (*i)->nameOut(os); FIXME, change access spec. for nameOut
664 os << '[' << (*i)->name() << "]\n";
665 (*i)->serialize(os);
666 }
667}
668
669void
670CxxConfigManager::loadState(CheckpointIn &checkpoint)
671{
672 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++ i)
673 (*i)->loadState(checkpoint);
674}
675
676void
677CxxConfigManager::deleteObjects()
678{
679 for (auto i = objectsInOrder.rbegin(); i != objectsInOrder.rend(); ++i) {
680 DPRINTF(CxxConfig, "Freeing sim object: %s\n", (*i)->name());
681 delete *i;
682 }
683
684 for (auto i = objectParamsByName.rbegin();
685 i != objectParamsByName.rend(); ++i)
686 {
687 CxxConfigParams *params = (*i).second;
688
689 DPRINTF(CxxConfig, "Freeing sim object params: %s\n",
690 params->getName());
691 delete params;
692 }
693
694 objectsInOrder.clear();
695 objectsByName.clear();
696}
697
698void
699CxxConfigManager::setParam(const std::string &object_name,
700 const std::string &param_name, const std::string &param_value)
701{
702 CxxConfigParams *params = findObjectParams(object_name);
703
704 if (!params->setParam(param_name, param_value, flags)) {
705 throw Exception(object_name, csprintf("Bad parameter value:"
706 " .%s=X=\"%s\"", param_name, param_value));
707 } else {
708 std::string instance_name = rename(object_name);
709
710 DPRINTF(CxxConfig, "Setting parameter %s.%s=%s\n",
711 instance_name, param_name, param_value);
712 }
713}
714
715void
716CxxConfigManager::setParamVector(const std::string &object_name,
717 const std::string &param_name,
718 const std::vector<std::string> &param_values)
719{
720 CxxConfigParams *params = findObjectParams(object_name);
721
722 if (!params->setParamVector(param_name, param_values, flags)) {
723 throw Exception(object_name, csprintf("Bad vector parameter value:"
724 " .%s=X=\"%s\"", param_name, formatParamList(param_values)));
725 } else {
726 std::string instance_name = rename(object_name);
727
728 DPRINTF(CxxConfig, "Setting parameter %s.%s=\"%s\"\n",
729 instance_name, param_name, formatParamList(param_values));
730 }
731}
732
733void CxxConfigManager::addRenaming(const Renaming &renaming)
734{
735 renamings.push_back(renaming);
736}
47#include "debug/CxxConfig.hh"
48#include "mem/mem_object.hh"
49#include "sim/serialize.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> &param_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 /* Sort the object names to get a consistent initialisation order
419 * even with config file reorganisation */
420 std::sort(objects.begin(), objects.end());
421
422 for (auto i = objects.begin(); i != objects.end(); ++i)
423 findObject(*i);
424
425 /* Set the traversal order for further iterators */
426 objectsInOrder.clear();
427 findTraversalOrder("root");
428}
429
430void
431CxxConfigManager::findTraversalOrder(const std::string &object_name)
432{
433 SimObject *object = findObject(object_name);
434
435 if (object) {
436 objectsInOrder.push_back(object);
437
438 std::vector<std::string> children;
439 configFile.getObjectChildren(object_name, children, true);
440
441 /* Visit all your children */
442 for (auto i = children.begin(); i != children.end(); ++i)
443 findTraversalOrder(*i);
444 }
445}
446
447void
448CxxConfigManager::bindAllPorts()
449{
450 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++i)
451 bindObjectPorts(*i);
452}
453
454void
455CxxConfigManager::bindPort(
456 SimObject *master_object, const std::string &master_port_name,
457 PortID master_port_index,
458 SimObject *slave_object, const std::string &slave_port_name,
459 PortID slave_port_index)
460{
461 MemObject *master_mem_object = dynamic_cast<MemObject *>(master_object);
462 MemObject *slave_mem_object = dynamic_cast<MemObject *>(slave_object);
463
464 if (!master_mem_object) {
465 throw Exception(master_object->name(), csprintf(
466 "Object isn't a mem object and so can have master port:"
467 " %s[%d]", master_port_name, master_port_index));
468 }
469
470 if (!slave_mem_object) {
471 throw Exception(slave_object->name(), csprintf(
472 "Object isn't a mem object and so can have slave port:"
473 " %s[%d]", slave_port_name, slave_port_index));
474 }
475
476 /* FIXME, check slave_port_index against connection_count
477 * defined for port, need getPortConnectionCount and a
478 * getCxxConfigDirectoryEntry for each object. */
479
480 /* It would be nice to be able to catch the errors from these calls. */
481 BaseMasterPort &master_port = master_mem_object->getMasterPort(
482 master_port_name, master_port_index);
483 BaseSlavePort &slave_port = slave_mem_object->getSlavePort(
484 slave_port_name, slave_port_index);
485
486 if (master_port.isConnected()) {
487 throw Exception(master_object->name(), csprintf(
488 "Master port: %s[%d] is already connected\n", master_port_name,
489 master_port_index));
490 }
491
492 if (slave_port.isConnected()) {
493 throw Exception(slave_object->name(), csprintf(
494 "Slave port: %s[%d] is already connected\n", slave_port_name,
495 slave_port_index));
496 }
497
498 DPRINTF(CxxConfig, "Binding port %s.%s[%d]"
499 " to %s:%s[%d]\n",
500 master_object->name(), master_port_name, master_port_index,
501 slave_object->name(), slave_port_name, slave_port_index);
502
503 master_port.bind(slave_port);
504}
505
506void
507CxxConfigManager::bindMasterPort(SimObject *object,
508 const CxxConfigDirectoryEntry::PortDesc &port,
509 const std::vector<std::string> &peers)
510{
511 unsigned int master_port_index = 0;
512
513 for (auto peer_i = peers.begin(); peer_i != peers.end();
514 ++peer_i)
515 {
516 const std::string &peer = *peer_i;
517 std::string slave_object_name;
518 std::string slave_port_name;
519 unsigned int slave_port_index;
520
521 parsePort(peer, slave_object_name, slave_port_name,
522 slave_port_index);
523
524 std::string slave_instance_name = rename(slave_object_name);
525
526 if (objectsByName.find(slave_instance_name) == objectsByName.end()) {
527 throw Exception(object->name(), csprintf(
528 "Can't find slave port object: %s", slave_instance_name));
529 }
530
531 SimObject *slave_object = objectsByName[slave_instance_name];
532
533 bindPort(object, port.name, master_port_index,
534 slave_object, slave_port_name, slave_port_index);
535
536 master_port_index++;
537 }
538}
539
540void
541CxxConfigManager::bindObjectPorts(SimObject *object)
542{
543 /* We may want to separate object->name() from the name in configuration
544 * later to allow (for example) repetition of fragments of configs */
545 const std::string &instance_name = object->name();
546
547 std::string object_name = unRename(instance_name);
548
549 std::string object_type;
550 const CxxConfigDirectoryEntry &entry =
551 findObjectType(object_name, object_type);
552
553 DPRINTF(CxxConfig, "Binding ports of object: %s (%s)\n",
554 instance_name, object_type);
555
556 for (auto i = entry.ports.begin(); i != entry.ports.end(); ++i) {
557 const CxxConfigDirectoryEntry::PortDesc *port = (*i).second;
558
559 DPRINTF(CxxConfig, "Binding port: %s.%s\n", instance_name,
560 port->name);
561
562 std::vector<std::string> peers;
563 configFile.getPortPeers(object_name, port->name, peers);
564
565 /* Only handle master ports as binding only needs to happen once
566 * for each observed pair of ports */
567 if (port->isMaster) {
568 if (!port->isVector && peers.size() > 1) {
569 throw Exception(instance_name, csprintf(
570 "Too many connections to non-vector port %s (%d)\n",
571 port->name, peers.size()));
572 }
573
574 bindMasterPort(object, *port, peers);
575 }
576 }
577}
578
579void
580CxxConfigManager::parsePort(const std::string &inp,
581 std::string &path, std::string &port, unsigned int &index)
582{
583 std::size_t dot_i = inp.rfind('.');
584 std::size_t open_square_i = inp.rfind('[');
585
586 if (dot_i == std::string::npos) {
587 DPRINTF(CxxConfig, "Bad port string: %s\n", inp);
588 path = "";
589 port = "";
590 index = 0;
591 } else {
592 path = std::string(inp, 0, dot_i);
593
594 if (open_square_i == std::string::npos) {
595 /* Singleton port */
596 port = std::string(inp, dot_i + 1, inp.length() - dot_i);
597 index = 0;
598 } else {
599 /* Vectored port elemnt */
600 port = std::string(inp, dot_i + 1, (open_square_i - 1) - dot_i);
601 index = std::atoi(inp.c_str() + open_square_i + 1);
602 }
603 }
604}
605
606void
607CxxConfigManager::forEachObject(void (SimObject::*mem_func)())
608{
609 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++i)
610 ((*i)->*mem_func)();
611}
612
613void
614CxxConfigManager::instantiate(bool build_all)
615{
616 if (build_all) {
617 findAllObjects();
618 bindAllPorts();
619 }
620
621 DPRINTF(CxxConfig, "Initialising all objects\n");
622 forEachObject(&SimObject::init);
623
624 DPRINTF(CxxConfig, "Registering stats\n");
625 forEachObject(&SimObject::regStats);
626
627 DPRINTF(CxxConfig, "Registering probe points\n");
628 forEachObject(&SimObject::regProbePoints);
629
630 DPRINTF(CxxConfig, "Connecting probe listeners\n");
631 forEachObject(&SimObject::regProbeListeners);
632}
633
634void
635CxxConfigManager::initState()
636{
637 DPRINTF(CxxConfig, "Calling initState on all objects\n");
638 forEachObject(&SimObject::initState);
639}
640
641void
642CxxConfigManager::startup()
643{
644 DPRINTF(CxxConfig, "Starting up all objects\n");
645 forEachObject(&SimObject::startup);
646}
647
648unsigned int
649CxxConfigManager::drain()
650{
651 return DrainManager::instance().tryDrain() ? 0 : 1;
652}
653
654void
655CxxConfigManager::drainResume()
656{
657 DrainManager::instance().resume();
658}
659
660void
661CxxConfigManager::serialize(std::ostream &os)
662{
663 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++ i) {
664 // (*i)->nameOut(os); FIXME, change access spec. for nameOut
665 os << '[' << (*i)->name() << "]\n";
666 (*i)->serialize(os);
667 }
668}
669
670void
671CxxConfigManager::loadState(CheckpointIn &checkpoint)
672{
673 for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++ i)
674 (*i)->loadState(checkpoint);
675}
676
677void
678CxxConfigManager::deleteObjects()
679{
680 for (auto i = objectsInOrder.rbegin(); i != objectsInOrder.rend(); ++i) {
681 DPRINTF(CxxConfig, "Freeing sim object: %s\n", (*i)->name());
682 delete *i;
683 }
684
685 for (auto i = objectParamsByName.rbegin();
686 i != objectParamsByName.rend(); ++i)
687 {
688 CxxConfigParams *params = (*i).second;
689
690 DPRINTF(CxxConfig, "Freeing sim object params: %s\n",
691 params->getName());
692 delete params;
693 }
694
695 objectsInOrder.clear();
696 objectsByName.clear();
697}
698
699void
700CxxConfigManager::setParam(const std::string &object_name,
701 const std::string &param_name, const std::string &param_value)
702{
703 CxxConfigParams *params = findObjectParams(object_name);
704
705 if (!params->setParam(param_name, param_value, flags)) {
706 throw Exception(object_name, csprintf("Bad parameter value:"
707 " .%s=X=\"%s\"", param_name, param_value));
708 } else {
709 std::string instance_name = rename(object_name);
710
711 DPRINTF(CxxConfig, "Setting parameter %s.%s=%s\n",
712 instance_name, param_name, param_value);
713 }
714}
715
716void
717CxxConfigManager::setParamVector(const std::string &object_name,
718 const std::string &param_name,
719 const std::vector<std::string> &param_values)
720{
721 CxxConfigParams *params = findObjectParams(object_name);
722
723 if (!params->setParamVector(param_name, param_values, flags)) {
724 throw Exception(object_name, csprintf("Bad vector parameter value:"
725 " .%s=X=\"%s\"", param_name, formatParamList(param_values)));
726 } else {
727 std::string instance_name = rename(object_name);
728
729 DPRINTF(CxxConfig, "Setting parameter %s.%s=\"%s\"\n",
730 instance_name, param_name, formatParamList(param_values));
731 }
732}
733
734void CxxConfigManager::addRenaming(const Renaming &renaming)
735{
736 renamings.push_back(renaming);
737}