The Sparta Modeling Framework
Loading...
Searching...
No Matches
ExampleSimulation.cpp
1// <Simulation.cpp> -*- C++ -*-
2
3
4#include <iostream>
5
6
7#include "ExampleSimulation.hpp"
8#include "Core.hpp"
9#include "CPUFactory.hpp"
10
12#include "sparta/utils/TimeManager.hpp"
15#include "sparta/trigger/ContextCounterTrigger.hpp"
21
22#include "Fetch.hpp"
23#include "Decode.hpp"
24#include "Rename.hpp"
25#include "Dispatch.hpp"
26#include "Execute.hpp"
27#include "LSU.hpp"
28#include "ROB.hpp"
29#include "FlushManager.hpp"
30#include "Preloader.hpp"
31#include "CustomHistogramStats.hpp"
32
33// UPDATE
34#include "BIU.hpp"
35#include "MSS.hpp"
36
37namespace sparta {
38
39 // Example parameter set used to reproduce write-final-config
41 public:
42 IntParameterSet(TreeNode * parent) :
43 ParameterSet(parent),
44 int_param_(new Parameter<uint32_t>(
45 "baz", 0, "Example parameter set to reproduce bug"))
46 {
47 addParameter_(int_param_.get());
48 }
49
50 uint32_t read() const {
51 return int_param_->getValue();
52 }
53
54 private:
55 std::unique_ptr<Parameter<uint32_t>> int_param_;
56 };
57
58 // Dummy node class used together with IntParameterSet to
59 // reproduce write-final-config bug
60 class Baz : public TreeNode {
61 public:
62 Baz(TreeNode* parent,
63 const std::string & desc) :
64 TreeNode(parent, "baz_node", "BazGroup", 0, desc)
65 {
66 baz_.reset(new IntParameterSet(this));
67 }
68
69 void readParams() {
70 std::cout << " Node '" << getLocation()
71 << "' has parameter 'baz' with a value set to "
72 << baz_->read() << std::endl;
73 auto ext = getExtension("baz_ext");
74 if(ext) {
75 std::cout << "That's the ticket: "
76 << ext->getParameters()->getParameterValueAs<std::string>("ticket_") << std::endl;
77 }
78 }
79
80 private:
81 std::unique_ptr<IntParameterSet> baz_;
82 };
83
84}
85
87{
88public:
90 virtual ~CircleExtensions() {}
91
92 void doSomethingElse() const {
93 std::cout << "Invoking a method that is unknown to the sparta::TreeNode object, "
94 "even though 'this' object was created by, and currently owned by, "
95 "a specific tree node.";
96 }
97
98private:
99
100 // Note: this parameter is NOT in the yaml config file,
101 // but subclasses can provide any parameter type supported
102 // by sparta::Parameter<T> which may be too complicated to
103 // clearly describe using simple yaml syntax
104 std::unique_ptr<sparta::Parameter<double>> degrees_;
105
106 // The base class will clobber together whatever parameter values it
107 // found in the yaml file, and give us a chance to add custom parameters
108 // to the same set
109 virtual void postCreate() override {
110 sparta::ParameterSet * ps = getParameters();
111 degrees_.reset(new sparta::Parameter<double>(
112 "degrees_", 360.0, "Number of degrees in a circle", ps));
113 }
114};
115
116double calculateAverageOfInternalCounters(
117 const std::vector<const sparta::CounterBase*> & counters)
118{
119 double agg = 0;
120 for (const auto & ctr : counters) {
121 agg += ctr->get();
122 }
123 return agg / counters.size();
124}
125
126ExampleSimulator::ExampleSimulator(const std::string& topology,
127 sparta::Scheduler & scheduler,
128 uint32_t num_cores,
129 uint64_t instruction_limit,
130 bool show_factories) :
131 sparta::app::Simulation("sparta_core_example", &scheduler),
132 cpu_topology_(topology),
133 num_cores_(num_cores),
134 instruction_limit_(instruction_limit),
135 show_factories_(show_factories)
136{
137 // Set up the CPU Resource Factory to be available through ResourceTreeNode
139
140 // Set up all node extension factories to be available during the simulation
141 // - This is only needed for parameter sets that also want to add some methods
142 // to their tree node extension, and/or for those that want to extend node
143 // parameter sets with more complicated sparta::Parameter<T> data types
144 addTreeNodeExtensionFactory_("circle", [](){return new CircleExtensions;});
145
146 // Initialize example simulation controller
147 controller_.reset(new ExampleSimulator::ExampleController(this));
149
150 // Register a custom calculation method for 'combining' a context counter's
151 // internal counters into one number. In this example simulator, let's just
152 // use an averaging function called "avg" which we can then invoke from report
153 // definition YAML files.
154 sparta::trigger::ContextCounterTrigger::registerContextCounterCalcFunction(
155 "avg", &calculateAverageOfInternalCounters);
156}
157
158void ExampleSimulator::registerStatCalculationFcns_()
159{
160 REGISTER_HISTOGRAM_STAT_CALC_FCN(CycleHistogramTreeNode, stdev_x3);
161 REGISTER_HISTOGRAM_STAT_CALC_FCN(CycleHistogramTreeNode, fraction_coverage_greaterThan2StdDev);
162 REGISTER_HISTOGRAM_STAT_CALC_FCN(CycleHistogramTreeNode, fraction_coverage_mean_p_StdDev_mean_p_2StdDev);
163 REGISTER_HISTOGRAM_STAT_CALC_FCN(CycleHistogramTreeNode, fraction_coverage_mean_mean_p_StdDev);
164 REGISTER_HISTOGRAM_STAT_CALC_FCN(CycleHistogramTreeNode, fraction_coverage_mean_m_StdDev_mean);
165 REGISTER_HISTOGRAM_STAT_CALC_FCN(CycleHistogramTreeNode, fraction_coverage_mean_m_2StdDev_mean_m_StdDev);
166 REGISTER_HISTOGRAM_STAT_CALC_FCN(CycleHistogramTreeNode, fraction_coverage_lesserThan2StdDev);
167 REGISTER_HISTOGRAM_STAT_CALC_FCN(HistogramTreeNode, stdev_x3_h);
168 REGISTER_HISTOGRAM_STAT_CALC_FCN(HistogramTreeNode, fraction_coverage_greaterThan2StdDev_h);
169 REGISTER_HISTOGRAM_STAT_CALC_FCN(HistogramTreeNode, fraction_coverage_mean_p_StdDev_mean_p_2StdDev_h);
170 REGISTER_HISTOGRAM_STAT_CALC_FCN(HistogramTreeNode, fraction_coverage_mean_mean_p_StdDev_h);
171 REGISTER_HISTOGRAM_STAT_CALC_FCN(HistogramTreeNode, fraction_coverage_mean_m_StdDev_mean_h);
172 REGISTER_HISTOGRAM_STAT_CALC_FCN(HistogramTreeNode, fraction_coverage_mean_m_2StdDev_mean_m_StdDev_h);
173 REGISTER_HISTOGRAM_STAT_CALC_FCN(HistogramTreeNode, fraction_coverage_lesserThan2StdDev_h);
174}
175
176ExampleSimulator::~ExampleSimulator()
177{
178 getRoot()->enterTeardown(); // Allow deletion of nodes without error now
179 if (on_triggered_notifier_registered_) {
180 getRoot()->DEREGISTER_FOR_NOTIFICATION(
181 onTriggered_, std::string, "sparta_expression_trigger_fired");
182 }
183}
184
186auto ExampleSimulator::getCPUFactory_() -> core_example::CPUFactory*{
187 auto sparta_res_factory = getResourceSet()->getResourceFactory("cpu");
188 auto cpu_factory = dynamic_cast<core_example::CPUFactory*>(sparta_res_factory);
189 return cpu_factory;
190}
191
192void ExampleSimulator::buildTree_()
193{
194 // TREE_BUILDING Phase. See sparta::PhasedObject::TreePhase
195 // Register all the custom stat calculation functions with (cycle)histogram nodes
196 registerStatCalculationFcns_();
197
198 auto cpu_factory = getCPUFactory_();
199
200 // Set the cpu topology that will be built
201 cpu_factory->setTopology(cpu_topology_, num_cores_);
202
203 // Create a single CPU
205 "cpu",
208 "CPU Node",
209 cpu_factory);
210 to_delete_.emplace_back(cpu_tn);
211
212 // Tell the factory to build the resources now
213 cpu_factory->buildTree(getRoot());
214
215 // Print the registered factories
216 if(show_factories_){
217 std::cout << "Registered factories: \n";
218 for(const auto& f : getCPUFactory_()->getResourceNames()){
219 std::cout << "\t" << f << std::endl;
220 }
221 }
222
223 // Validate tree node extensions during tree building
224 for(uint32_t i = 0; i < num_cores_; ++i){
225 const std::string dispatch_loc = "cpu.core" + std::to_string(i) + ".dispatch";
226 const std::string alu0_loc = "cpu.core" + std::to_string(i) + ".alu0";
227 const std::string alu1_loc = "cpu.core" + std::to_string(i) + ".alu1";
228 const std::string fpu_loc = "cpu.core" + std::to_string(i) + ".fpu";
229
230 // user_data.when_ (dispatch)
231 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(dispatch_loc), "when_", "user_data")) {
232 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
233 return val == "buildTree_";
234 }, "Parameter 'when_' should be 'buildTree_'");
235 }
236
237 // user_data.why_ (dispatch)
238 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(dispatch_loc), "why_", "user_data")) {
239 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
240 return val == "checkAvailability";
241 }, "Parameter 'why_' should be 'checkAvailability'");
242 }
243
244 // square.edges_ (dispatch)
245 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(dispatch_loc), "edges_", "square")) {
246 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
247 return val == "4";
248 }, "Parameter 'edges_' should be '4'");
249 }
250
251 // difficulty.color_ (alu0)
252 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(alu0_loc), "color_", "difficulty")) {
253 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
254 return val == "black";
255 }, "Parameter 'color_' should be 'black'");
256 }
257
258 // difficulty.shape_ (alu0)
259 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(alu0_loc), "shape_", "difficulty")) {
260 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
261 return val == "diamond";
262 }, "Parameter 'shape_' should be 'diamond'");
263 }
264
265 // difficulty.color_ (alu1)
266 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(alu1_loc), "color_", "difficulty")) {
267 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
268 return val == "green";
269 }, "Parameter 'color_' should be 'green'");
270 }
271
272 // difficulty.shape_ (alu1)
273 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(alu1_loc), "shape_", "difficulty")) {
274 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
275 return val == "circle";
276 }, "Parameter 'shape_' should be 'circle'");
277 }
278
279 // circle.color_ (fpu)
280 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(fpu_loc), "color_", "circle")) {
281 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
282 return val == "green";
283 }, "Parameter 'color_' should be 'green'");
284 }
285
286 // circle.shape_ (fpu)
287 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(fpu_loc), "shape_", "circle")) {
288 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
289 return val == "round";
290 }, "Parameter 'shape_' should be 'round'");
291 }
292
293 // circle.degrees_ (fpu)
294 if (auto prm = getExtensionParameter_<double>(getRoot()->getChild(fpu_loc), "degrees_", "circle")) {
295 prm->addDependentValidationCallback([](double & val, const sparta::TreeNode*) -> bool {
296 return val == 360.0;
297 }, "Parameter 'degrees_' should be 360.0");
298 }
299
300 // circle.edges_ (fpu)
301 if (auto prm = getExtensionParameter_<std::string>(getRoot()->getChild(fpu_loc), "edges_", "circle")) {
302 prm->addDependentValidationCallback([](std::string & val, const sparta::TreeNode*) -> bool {
303 return val == "0";
304 }, "Parameter 'edges_' should be '0'");
305 }
306
307 // User-specified extension class
308 getExtension_<CircleExtensions>(getRoot()->getChild(fpu_loc), "circle")->doSomethingElse();
309 }
310
311 // Attach two tree nodes to get the following:
312 // top
313 // core0
314 // dispatch
315 // baz_node
316 // params
317 // baz
318 // fpu
319 // baz_node
320 // params
321 // baz
322 //
323 // This is needed to reproduce a write-final-config bug where an arch file
324 // specifies 'top.core0.*.baz_node.params.baz: 300' and the ConfigEmitterYAML
325 // ends up throwing an exception due to the '*' which tripped up the tree node
326 // extensions code.
327 auto dispatch = getRoot()->getChild("cpu.core0.dispatch");
328 auto fpu = getRoot()->getChild("cpu.core0.fpu");
329
330 dispatch_baz_.reset(new sparta::Baz(
331 dispatch, "Dummy node under top.cpu.core0.dispatch (to reproduce a SPARTA bug)"));
332
333 fpu_baz_.reset(new sparta::Baz(
334 fpu, "Dummy node under top.cpu.core0.fpu (to reproduce a SPARTA bug)"));
335}
336
337void ExampleSimulator::configureTree_()
338{
339 validateTreeNodeExtensions_();
340
341 // In TREE_CONFIGURING phase
342 // Configuration from command line is already applied
343
344 // Read these parameter values to avoid 'unread unbound parameter' exceptions:
345 // top.cpu.core0.dispatch.baz_node.params.baz
346 // top.cpu.core0.fpu.baz_node.params.baz
347 dispatch_baz_->readParams();
348 fpu_baz_->readParams();
349
350 sparta::ParameterBase* max_instrs =
351 getRoot()->getChildAs<sparta::ParameterBase>("cpu.core0.rob.params.num_insts_to_retire");
352
353 // Safely assign as string for now in case parameter type changes.
354 // Direct integer assignment without knowing parameter type is not yet available through C++ API
355 if(instruction_limit_ != 0){
356 max_instrs->setValueFromString(sparta::utils::uint64_to_str(instruction_limit_));
357 }
358
359 testing_notification_source_.reset(new sparta::NotificationSource<uint64_t>(
360 this->getRoot()->getSearchScope()->getChild("top.cpu.core0.rob"),
361 "testing_notif_channel",
362 "Notification channel for testing purposes only",
363 "testing_notif_channel"));
364
365 toggle_trigger_notification_source_.reset(new sparta::NotificationSource<uint64_t>(
366 getRoot()->getSearchScope()->getChild("top.cpu.core0.rob"),
367 "stats_profiler",
368 "Notification channel for testing report toggling on/off (statistics profiling)",
369 "stats_profiler"));
370
371 legacy_warmup_report_starter_.reset(new sparta::NotificationSource<uint64_t>(
372 getRoot(),
373 "all_threads_warmup_instruction_count_retired_re4",
374 "Legacy notificiation channel for testing purposes only",
375 "all_threads_warmup_instruction_count_retired_re4"));
376
377 getRoot()->REGISTER_FOR_NOTIFICATION(
378 onTriggered_, std::string, "sparta_expression_trigger_fired");
379 on_triggered_notifier_registered_ = true;
380}
381
382void ExampleSimulator::bindTree_()
383{
384 // In TREE_FINALIZED phase
385 // Tree is finalized. Taps placed. No new nodes at this point
386 // Bind appropriate ports
387
388 //Tell the factory to bind all units
389 auto cpu_factory = getCPUFactory_();
390 cpu_factory->bindTree(getRoot());
391
392 sparta::SpartaHandler cb = sparta::SpartaHandler::from_member<
393 ExampleSimulator, &ExampleSimulator::postRandomNumber_>(
394 this, "ExampleSimulator::postRandomNumber_");
395
396 random_number_trigger_.reset(new sparta::trigger::ExpressionCounterTrigger(
397 "RandomNumber", cb, "cpu.core0.rob.stats.total_number_retired 7500", false, this->getRoot()));
398
399 toggle_notif_trigger_.reset(new sparta::trigger::ExpressionTimeTrigger(
400 "ToggleNotif",
401 CREATE_SPARTA_HANDLER(ExampleSimulator, postToToggleTrigger_),
402 "1 ns",
403 getRoot()));
404
405 static const uint32_t warmup_multiplier = 1000;
406 auto gen_expression = [](const uint32_t core_idx) {
407 std::ostringstream oss;
408 oss << "cpu.core" << core_idx << ".rob.stats.total_number_retired >= "
409 << ((core_idx+1) * warmup_multiplier);
410 return oss.str();
411 };
412
413 num_cores_still_warming_up_ = num_cores_;
414 core_warmup_listeners_.reserve(num_cores_);
415
416 for (uint32_t core_idx = 0; core_idx < num_cores_; ++core_idx) {
417 core_warmup_listeners_.emplace_back(
418 new sparta::trigger::ExpressionTrigger(
419 "LegacyWarmupNotifications",
420 CREATE_SPARTA_HANDLER(ExampleSimulator, onLegacyWarmupNotification_),
421 gen_expression(core_idx),
422 getRoot(),
423 nullptr));
424 }
425}
426
427void ExampleSimulator::onLegacyWarmupNotification_()
428{
429 sparta_assert(num_cores_still_warming_up_ > 0);
430 --num_cores_still_warming_up_;
431 if (num_cores_still_warming_up_ == 0) {
432 legacy_warmup_report_starter_->postNotification(1);
433 }
434}
435
436const sparta::CounterBase* ExampleSimulator::findSemanticCounter_(CounterSemantic sem) const {
437 switch(sem){
439 return getRoot()->getChildAs<const sparta::CounterBase>("cpu.core0.rob.stats.total_number_retired");
440 break;
441 default:
442 return nullptr;
443 }
444}
445
446void ExampleSimulator::postRandomNumber_()
447{
448 const size_t random = rand() % 25;
449 testing_notification_source_->postNotification(random);
450 random_number_trigger_->reschedule();
451}
452
453void ExampleSimulator::postToToggleTrigger_()
454{
455 typedef std::pair<uint64_t,uint64_t> ValueCount;
456 static std::queue<ValueCount> values;
457
458 if (values.empty()) {
459 values.push({0,15});
460 values.push({1,25});
461 values.push({0,15});
462 values.push({1,25});
463 values.push({0,15});
464
465 ValueCount tmp = values.front();
466 values.push(tmp);
467 }
468
469 if (values.front().second == 0) {
470 values.pop();
471 ValueCount tmp = values.front();
472 values.push(tmp);
473 } else {
474 --values.front().second;
475 }
476
477 const ValueCount & current_value = values.front();
478 const uint64_t value_to_post = current_value.first;
479 toggle_trigger_notification_source_->postNotification(value_to_post);
480 toggle_notif_trigger_->reschedule();
481}
482
483void ExampleSimulator::onTriggered_(const std::string & msg)
484{
485 std::cout << " [trigger] " << msg << std::endl;
486}
487
488template <typename ParamT>
489sparta::Parameter<ParamT>* ExampleSimulator::getExtensionParameter_(
490 sparta::TreeNode* node,
491 const std::string& param_name,
492 const std::string& ext_name)
493{
494 if (!node) {
495 return nullptr;
496 }
497
498 sparta::TreeNode::ExtensionsBase * ext = ext_name.empty() ?
499 node->getExtension() :
500 node->getExtension(ext_name);
501
502 if (!ext) {
503 return nullptr;
504 }
505
506 sparta::ParameterSet * params = ext->getParameters();
507 if (!params) {
508 return nullptr;
509 }
510
511 if (!params->hasParameter(param_name)) {
512 return nullptr;
513 }
514
515 return &params->getParameterAs<ParamT>(param_name);
516}
517
518template <typename ExtensionT>
519ExtensionT* ExampleSimulator::getExtension_(
520 sparta::TreeNode* node,
521 const std::string& ext_name)
522{
523 static_assert(std::is_base_of<sparta::TreeNode::ExtensionsBase, ExtensionT>::value,
524 "ExtensionT must be derived from sparta::TreeNode::ExtensionsBase");
525
526 if (!node) {
527 return nullptr;
528 }
529
530 return ext_name.empty() ?
531 dynamic_cast<ExtensionT*>(node->getExtension()) :
532 dynamic_cast<ExtensionT*>(node->getExtension(ext_name));
533}
534
535void ExampleSimulator::validateTreeNodeExtensions_()
536{
537 // cat.name_
538 if (auto prm = getExtensionParameter_<std::string>(
539 getRoot()->getChild("cpu.core0.lsu"), "name_", "cat"))
540 {
541 prm->addDependentValidationCallback(
542 [](std::string & val, const sparta::TreeNode*) -> bool {
543 return val == "Tom";
544 }, "Parameter 'name_' should be 'Tom'");
545 }
546
547 // cat.language_
548 if (auto prm = getExtensionParameter_<std::string>(
549 getRoot()->getChild("cpu.core0.lsu"), "language_", "cat"))
550 {
551 prm->addDependentValidationCallback(
552 [](std::string & val, const sparta::TreeNode*) -> bool {
553 return val == "meow" || val == "grrr";
554 }, "Parameter 'language_' should be 'meow' or 'grrr'");
555 }
556
557 // mouse.name_
558 if (auto prm = getExtensionParameter_<std::string>(
559 getRoot()->getChild("cpu.core0.lsu"), "name_", "mouse"))
560 {
561 prm->addDependentValidationCallback(
562 [](std::string & val, const sparta::TreeNode*) -> bool {
563 return val == "Jerry";
564 }, "Parameter 'name_' should be 'Jerry'");
565 }
566
567 // mouse.language_
568 if (auto prm = getExtensionParameter_<std::string>(
569 getRoot()->getChild("cpu.core0.lsu"), "language_", "mouse"))
570 {
571 prm->addDependentValidationCallback(
572 [](std::string & val, const sparta::TreeNode*) -> bool {
573 return val == "squeak";
574 }, "Parameter 'language_' should be 'squeak'");
575 }
576
577 // circle.color_
578 if (auto prm = getExtensionParameter_<std::string>(
579 getRoot()->getChild("cpu.core0.fpu"), "color_", "circle"))
580 {
581 prm->addDependentValidationCallback(
582 [](std::string & val, const sparta::TreeNode*) -> bool {
583 return val == "green";
584 }, "Parameter 'color_' should be 'green'");
585 }
586
587 // circle.shape_
588 if (auto prm = getExtensionParameter_<std::string>(
589 getRoot()->getChild("cpu.core0.fpu"), "shape_", "circle"))
590 {
591 prm->addDependentValidationCallback(
592 [](std::string & val, const sparta::TreeNode*) -> bool {
593 return val == "round";
594 }, "Parameter 'shape_' should be 'round'");
595 }
596
597 // circle.degrees_
598 if (auto prm = getExtensionParameter_<double>(
599 getRoot()->getChild("cpu.core0.fpu"), "degrees_", "circle"))
600 {
601 prm->addDependentValidationCallback(
602 [](double & val, const sparta::TreeNode*) -> bool {
603 return val == 360.0;
604 }, "Parameter 'degrees_' should be 360.0");
605 }
606
607 // User-specified extension class
608 getExtension_<CircleExtensions>(getRoot()->getChild("cpu.core0.fpu"), "circle")->doSomethingElse();
609
610 // apple.color_
611 if (auto prm = getExtensionParameter_<std::string>(
612 getRoot(), "color_", "apple"))
613 {
614 prm->addDependentValidationCallback(
615 [](std::string & val, const sparta::TreeNode*) -> bool {
616 return val == "red";
617 }, "Parameter 'color_' should be 'red'");
618 }
619
620 // The 'core0.lsu' node has two named extensions, so asking that node for
621 // unqualified extensions (no name specified) should throw.
622 //
623 // Note that we still have to check if core0.lsu has multiple extensions,
624 // since it will have zero in most example simulations unless --extension-file
625 // was used.
626 auto core0_lsu = getRoot()->getChild("cpu.core0.lsu");
627 if (core0_lsu->getNumExtensions() > 1) {
628 bool threw = false;
629 try {
630 getExtension_<>(core0_lsu);
631 } catch (...) {
632 threw = true;
633 }
634
635 if (!threw) {
636 throw sparta::SpartaException("Expected an exception to be thrown for unqualified "
637 "call to TreeNode::getExtension()");
638 }
639 }
640
641 // <unnamed>.color_
642 if (auto prm = getExtensionParameter_<std::string>(
643 getRoot()->getChild("cpu.core0.fpu"), "color_"))
644 {
645 prm->addDependentValidationCallback(
646 [](std::string & val, const sparta::TreeNode*) -> bool {
647 return val == "green";
648 }, "Parameter 'color_' should be 'green'");
649 }
650
651 // <unnamed>.shape_
652 if (auto prm = getExtensionParameter_<std::string>(
653 getRoot()->getChild("cpu.core0.fpu"), "shape_"))
654 {
655 prm->addDependentValidationCallback(
656 [](std::string & val, const sparta::TreeNode*) -> bool {
657 return val == "round";
658 }, "Parameter 'shape_' should be 'round'");
659 }
660
661 // <unnamed>.degrees_
662 if (auto prm = getExtensionParameter_<double>(
663 getRoot()->getChild("cpu.core0.fpu"), "degrees_"))
664 {
665 prm->addDependentValidationCallback(
666 [](double & val, const sparta::TreeNode*) -> bool {
667 return val == 360.0;
668 }, "Parameter 'degrees_' should be 360.0");
669 }
670
671 // <unnamed>.edges_
672 if (auto prm = getExtensionParameter_<std::string>(
673 getRoot()->getChild("cpu.core0.fpu"), "edges_"))
674 {
675 prm->addDependentValidationCallback(
676 [](std::string & val, const sparta::TreeNode*) -> bool {
677 return val == "0";
678 }, "Parameter 'edges_' should be '0'");
679 }
680
681 // baz_ext.ticket_
682 if (auto prm = getExtensionParameter_<std::string>(
683 getRoot()->getChild("cpu.core0.dispatch.baz_node", false), "ticket_", "baz_ext"))
684 {
685 prm->addDependentValidationCallback(
686 [](std::string & val, const sparta::TreeNode*) -> bool {
687 return val == "663";
688 }, "Parameter 'ticket_' should be '663'");
689 }
690}
691
692ExampleSimulator::ExampleController::ExampleController(
693 const sparta::app::Simulation * sim) :
694 sparta::app::Simulation::SimulationController(sim)
695{
696 sparta::app::Simulation::SimulationController::addNamedCallback_(
697 "eat", CREATE_SPARTA_HANDLER(ExampleController, customEatCallback_));
698
699 sparta::app::Simulation::SimulationController::addNamedCallback_(
700 "sleep", CREATE_SPARTA_HANDLER(ExampleController, customSleepCallback_));
701}
702
703void ExampleSimulator::ExampleController::pause_(const sparta::app::Simulation * sim)
704{
705 std::cout << " [control] Controller PAUSE method has been called for simulation '"
706 << sim->getSimName() << "'" << std::endl;
707}
708
709void ExampleSimulator::ExampleController::resume_(const sparta::app::Simulation * sim)
710{
711 std::cout << " [control] Controller RESUME method has been called for simulation '"
712 << sim->getSimName() << "'" << std::endl;
713}
714
715void ExampleSimulator::ExampleController::terminate_(const sparta::app::Simulation * sim)
716{
717 std::cout << " [control] Controller TERMINATE method has been called for simulation '"
718 << sim->getSimName() << "'" << std::endl;
719 const_cast<sparta::Scheduler*>(sim->getScheduler())->stopRunning();
720}
721
722void ExampleSimulator::ExampleController::customEatCallback_()
723{
724 std::cout << " [control] Controller CUSTOM method has been called ('eat')" << std::endl;
725}
726
727void ExampleSimulator::ExampleController::customSleepCallback_()
728{
729 std::cout << " [control] Controller CUSTOM method has been called ('sleep')" << std::endl;
730}
File that defines the Clock class.
CycleHistogram implementation using sparta CycleCounter.
Definition of the CoreModel Fetch unit.
#define REGISTER_HISTOGRAM_STAT_CALC_FCN(histogram_type, fcn_name)
Function Registration Macro for Histogram/CycleHistogram. This macro is called by the users in their ...
Histogram implementation using sparta Counters.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
#define CREATE_SPARTA_HANDLER(clname, meth)
File that defines the SpartaTester class and testing Macros.
Cool string utilities.
Basic Node framework in sparta device tree composite pattern.
ExampleSimulator which builds the model and configures it.
ExampleSimulator(const std::string &topology, sparta::Scheduler &scheduler, uint32_t num_cores=1, uint64_t instruction_limit=0, bool show_factories=false)
Construct ExampleSimulator.
The base class for all Counters.
Helper class used to trivially extend TreeNode parameter sets (but not any additional functionality b...
A TreeNode that generates a specific type of notification which propagates up a tree of TreeNodes (us...
Non-templated base class for generic parameter access and iteration.
void setValueFromString(const std::string &str, bool poke=false)
Attempts to assign a value to this non-vector Parameter from a string.
Generic container of Parameters.
ParameterSet()=delete
Default constructor disabled.
void addParameter_(sparta::ParameterBase *p)
Add a parameter to the parameter set. \temp This will be removed.
bool hasParameter(const std::string &name) const
Determines whether this ParameterSet has the parameter with the given name.
const Parameter< ContentT > & getParameterAs(const std::string &name) const
Retrieves a sparta::Parameter<ContentT> reference from this parameter set.
Parameter instance, templated to contain only a specific type.
void addResourceFactory()
Add a resource factory by its template type.
TreeNode subclass representing a node in the device tree which contains a single ResourceFactory and ...
void enterTeardown()
Places this tree into TREE_TEARDOWN phase so that nodes may be deleted without errors.
A class that lets you schedule events now and in the future.
void stopRunning()
Tell the scheduler to stop running.
Used to construct and throw a standard C++ exception. Inherits from std::exception.
Base class used to extend TreeNode parameter sets.
Node in a composite tree representing a sparta Tree item.
Definition TreeNode.hpp:205
static const group_idx_type GROUP_IDX_NONE
GroupIndex indicating that a node has no group index because it belongs to no group.
Definition TreeNode.hpp:303
std::string getLocation() const override final
static constexpr char GROUP_NAME_NONE[]
Group name indicating that a node belongs to no group.
Definition TreeNode.hpp:314
TreeNode()=delete
Not default-constructable.
ExtensionsBase * getExtension()
Get an extension without needing to specify any particular type string. If no extensions exist,...
ExtensionsBase * getExtension(const std::string &extension_name)
Get an extension object by type string. Returns nullptr if not found (unrecognized).
const ConstT getChildAs(const std::string &name, bool must_exist=true) const
Retrieves a child that is castable to T with the given dotted path.
TreeNode * getChild(const std::string &name, bool must_exist=true)
Retrieves a child with this dotted path name.
Simulator which builds a sparta DeviceTree.
std::vector< std::unique_ptr< sparta::TreeNode > > to_delete_
Vector of TreeNodes to delete automatically at destruction. Add any nodes allocated to this list to a...
@ CSEM_INSTRUCTIONS
Instruction count semantic (usually core0)
std::shared_ptr< SimulationController > controller_
Custom controller to handle various simulation events.
sparta::RootTreeNode * getRoot() noexcept
Returns the tree root.
void addTreeNodeExtensionFactory_(const std::string &extension_name, std::function< TreeNode::ExtensionsBase *()> creator)
Include an extension factory for this simulation's device tree nodes. They will be given to specific ...
void setSimulationController_(std::shared_ptr< SimulationController > controller)
Set a controller to handle custom simulation events.
sparta::ResourceSet * getResourceSet() noexcept
Returns the resource set for this Simulation.
const std::string & getSimName() const noexcept
Returns this simulator's name.
sparta::Scheduler * getScheduler()
Returns the simulation's scheduler.
Macros for handling exponential backoff.