The Sparta Modeling Framework
Loading...
Searching...
No Matches
Precedence.hpp
Go to the documentation of this file.
1// <Precedence.hpp> -*- C++ -*-
2
3#pragma once
4
5#include <type_traits>
6
13#include "sparta/events/GlobalOrderingPoint.hpp"
14#include "sparta/ports/Port.hpp"
15#include "sparta/ports/Bus.hpp"
16
24namespace sparta
25{
27
104
106 // GOP -> EventNode types
108
136 template<class ScheduleableTypeA>
137 typename std::enable_if<std::is_base_of<EventNode, ScheduleableTypeA>::value, const GlobalOrderingPoint>::
138 type & operator>>(ScheduleableTypeA & producer, const GlobalOrderingPoint & consumer)
139 {
140 producer.getScheduleable().precedes(*consumer.getGOPoint());
141 return consumer;
142 }
143
171 template<class ScheduleableTypeA>
172 typename std::enable_if<std::is_base_of<EventNode, ScheduleableTypeA>::value, ScheduleableTypeA>::
173 type & operator>>(const GlobalOrderingPoint & producer, ScheduleableTypeA & consumer)
174 {
175 producer.getGOPoint()->precedes(consumer.getScheduleable());
176 return consumer;
177 }
178
206 inline InPort & operator>>(const GlobalOrderingPoint & producer, InPort & consumer) {
207 producer.getGOPoint()->precedes(consumer.getScheduleable_());
208 return consumer;
209 }
210
238 inline const GlobalOrderingPoint & operator>>(InPort & producer, const GlobalOrderingPoint & consumer) {
239 producer.getScheduleable_().precedes(*consumer.getGOPoint());
240 return consumer;
241 }
242
243#ifndef DO_NOT_DOCUMENT
244#define __SPARTA_PHASE_ERROR_MSG \
245 "\nERROR: You cannot set a precedence on two Scheduleable types" \
246 " that are on different phases. This will happen automatically by the framework."
247#endif
248
250 // Start with easy, concrete, derived types
252
254 // payloadevent_precedence PayloadEvent Precedence
255 // Examples of PayloadEvent precedence
256 //
257 // PayloadEvent<T, P> >> PayloadEvent<T, P>;
258 // PayloadEvent<T, P> >> UniqueEvent<P>;
259 // PayloadEvent<T, P> >> SingleCycleUniqueEvent<P>;
260 // PayloadEvent<T, P> >> Event<P>;
261 // UniqueEvent<P> >> PayloadEvent<T, P>;
262 // SingleCycleUniqueEvent<P> >> PayloadEvent<T, P>;
263 // Event<P> >> PayloadEvent<T, P>;
264 //
265
293 template<class DataT1, SchedulingPhase PayloadPhaseT1,
294 class DataT2, SchedulingPhase PayloadPhaseT2>
297 {
298 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
299 producer.getScheduleable().precedes(consumer.getScheduleable());
300 return consumer;
301 }
302
330 template<class DataT1,
331 SchedulingPhase PayloadPhaseT1,
332 SchedulingPhase PayloadPhaseT2>
335 {
336 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
337 producer.getScheduleable().precedes(consumer.getScheduleable());
338 return consumer;
339 }
340
368 template<class DataT1,
369 SchedulingPhase PayloadPhaseT1,
370 SchedulingPhase PayloadPhaseT2>
373 {
374 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
375 producer.getScheduleable().precedes(consumer.getScheduleable());
376 return consumer;
377 }
378
406 template<class DataT1,
407 SchedulingPhase PayloadPhaseT1,
408 SchedulingPhase PayloadPhaseT2>
410 Event<PayloadPhaseT2> & consumer)
411 {
412 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
413 producer.getScheduleable().precedes(consumer.getScheduleable());
414 return consumer;
415 }
416
444 template<SchedulingPhase PayloadPhaseT1,
445 class DataT2,
446 SchedulingPhase PayloadPhaseT2>
449 {
450 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
451 producer.precedes(consumer.getScheduleable());
452 return consumer;
453 }
454
482 template<SchedulingPhase PayloadPhaseT1,
483 class DataT2,
484 SchedulingPhase PayloadPhaseT2>
487 {
488 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
489 producer.precedes(consumer.getScheduleable());
490 return consumer;
491 }
492
520 template<SchedulingPhase PayloadPhaseT1,
521 class DataT2,
522 SchedulingPhase PayloadPhaseT2>
525 {
526 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
527 producer.precedes(consumer.getScheduleable());
528 return consumer;
529 }
530
532 // UniqueEvent Precedence
533 //
534 // UniqueEvent<P> >> UniqueEvent<P>;
535 // UniqueEvent<P> >> SingleCycleUniqueEvent<P>;
536 // SingleCycleUniqueEvent<P> >> UniqueEvent<P>;
537 //
538
566 template<SchedulingPhase PayloadPhaseT1,
567 SchedulingPhase PayloadPhaseT2>
570 {
571 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
572 producer.precedes(consumer.getScheduleable());
573 return consumer;
574 }
575
603 template<SchedulingPhase PayloadPhaseT1,
604 SchedulingPhase PayloadPhaseT2>
607 {
608 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
609 producer.precedes(consumer.getScheduleable());
610 return consumer;
611 }
612
640 template<SchedulingPhase PayloadPhaseT1,
641 SchedulingPhase PayloadPhaseT2>
644 {
645 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
646 producer.precedes(consumer.getScheduleable());
647 return consumer;
648 }
649
651 // SingleCycleUniqueEvent Precedence
652 //
680 template<SchedulingPhase PhaseT1, SchedulingPhase PhaseT2>
683 {
684 static_assert(PhaseT1 == PhaseT2, __SPARTA_PHASE_ERROR_MSG);
685 producer.getScheduleable().precedes(consumer.getScheduleable());
686 return consumer;
687 }
688
690 // Event Precedence
691 //
719 template<SchedulingPhase PhaseT1, SchedulingPhase PhaseT2>
721 {
722 static_assert(PhaseT1 == PhaseT2, __SPARTA_PHASE_ERROR_MSG);
723 producer.precedes(consumer.getScheduleable());
724 return consumer;
725 }
726
728 // // Unique Ptrs
729 // std::unique_ptr<eventT> >> std::unique_ptr<eventT>;
730 // std::unique_ptr<eventT> >> concrete_event;
731 // std::unique_ptr<eventT> >> event_pointer;
732 // concrete_event >> std::unique_ptr<eventT>;
733 // event_pointer >> std::unique_ptr<eventT>;
734
762 template<class EventT1, class EventT2>
763 std::unique_ptr<EventT2> & operator>>(std::unique_ptr<EventT1> & producer,
764 std::unique_ptr<EventT2> & consumer)
765 {
766 (*producer) >> (*consumer);
767 return consumer;
768 }
769
797 template<class EventT1, class EventT2>
798 std::unique_ptr<EventT2> & operator>>(EventT1 & producer, std::unique_ptr<EventT2> & consumer)
799 {
800 producer >> (*consumer);
801 return consumer;
802 }
803
831 template<class EventT1, class EventT2>
832 EventT2 & operator>>(std::unique_ptr<EventT1> & producer, EventT2 & consumer)
833 {
834 (*producer) >> consumer;
835 return consumer;
836 }
837
839 // Scheduleable <-> PayloadEvent
841
869 template<class DataT2, SchedulingPhase phase>
872 {
873 sparta_assert(producer.getSchedulingPhase() == consumer.getSchedulingPhase(),
874 __SPARTA_PHASE_ERROR_MSG);
875 producer.precedes(consumer.getScheduleable());
876 return consumer;
877 }
878
906 template<class DataT1, SchedulingPhase phase>
908 Scheduleable & consumer)
909 {
910 sparta_assert(consumer.getSchedulingPhase() == producer.getSchedulingPhase(),
911 __SPARTA_PHASE_ERROR_MSG);
912 producer.getScheduleable().precedes(consumer);
913 return consumer;
914 }
915
917 // Bus Support
919
920 // This is where an event must be scheduled before any events
921 // scheduled as a results of OutPorts on the Bus.
922
950 template<class ScheduleableType>
951 typename
952 std::enable_if<std::is_base_of<Scheduleable, ScheduleableType>::value, Bus>::
953 type & operator>>(ScheduleableType & producer, Bus & consumer)
954 {
955 consumer.outportsSucceed(producer);
956 return consumer;
957 }
958
959 // This is where an event must be scheduled after data arrival on
960 // InPorts within the Bus:
961 //
962 // my_incoming_bus >> ev_tick;
963 //
964
992 template<class ScheduleableType>
993 typename
994 std::enable_if<std::is_base_of<Scheduleable, ScheduleableType>::value, ScheduleableType>::
995 type & operator>>(Bus & producer, ScheduleableType & consumer)
996 {
997 producer.inportsPrecede(consumer);
998 return consumer;
999 }
1000
1002 // Add support for a group of event types
1004
1041 class EventGroup : public std::vector<Scheduleable *>
1042 {
1043 // Make sure no one is adding a Port in the mix (this was the
1044 // old framework)
1045 template<SchedulingPhase phase, class ScheduleableT, class ...ArgsT>
1046 typename std::enable_if<std::is_base_of<Port, ScheduleableT>::value, void>::
1047 type addScheduable_(ScheduleableT & /*port*/, ArgsT&... /*scheds*/) {
1048 static_assert(std::is_base_of<Port, ScheduleableT>::value,
1049 "\nERROR: You cannot set up a precedence between an Scheduleable type and a Port. "
1050 "\n\tIf you want to do this, register the Scheduleable with the Port using the "
1051 "registerConsumerEvent/registerProducingEvent method on the Port."
1052 "\n\tSee the SPARTA documentation for more information."
1053 "\n\tBTW, in this particular error, there is a Port type in the EventGroup that's bad");
1054 }
1055
1056 // Add a Scheduable type, not a PayloadEventType
1057 template<SchedulingPhase phase, class ScheduleableT, class ...ArgsT>
1058 typename std::enable_if<std::is_base_of<sparta::Scheduleable, ScheduleableT>::value, void>::
1059 type addScheduable_(ScheduleableT & sched, ArgsT&... scheds) {
1060 static_assert(phase == ScheduleableT::event_phase,
1061 "\nERROR: You cannot set a precedence on two Scheduleable types"
1062 " that are on different phases. This will happen automatically by the framework."
1063 "\n\tIn this particular error, there is a Scheduleable type in the EventGroup that's bad");
1064 emplace_back(&sched);
1065 addScheduable_<ScheduleableT::event_phase>(scheds...);
1066 }
1067
1068 // Need a specialization for PayloadEvents since they are not direct Scheduleables
1069 template<SchedulingPhase phase, class DataT, SchedulingPhase PLEPhase, class ...ArgsT>
1070 void addScheduable_(PayloadEvent<DataT, PLEPhase> & sched, ArgsT&... scheds) {
1071 static_assert(phase == PLEPhase,
1072 "\nERROR: You cannot set a precedence on two Scheduleable types"
1073 " that are on different phases. This will happen automatically by the framework."
1074 "\n\tIn this particular error, there is a PayloadEvent type in the EventGroup that's bad");
1075 emplace_back(&sched.getScheduleable());
1076 addScheduable_<PLEPhase>(scheds...);
1077 }
1078
1079 // end of list
1080 template<SchedulingPhase phase>
1081 void addScheduable_() {}
1082
1083 public:
1084
1098 template<class ScheduleableT, class ...ArgsT>
1099 explicit EventGroup(ScheduleableT & sched, ArgsT&...scheds) {
1100 static_assert(std::is_same<Port, ScheduleableT>::value == false,
1101 "\nERROR: You cannot add Ports to a precedence group as Ports do not support precedence. "
1102 "If you have a zero-cycle Port and a receiving event, register that event with the Port instead."
1103 "\n\tIn this particular error, there is a Port type in the EventGroup that's bad");
1104 static_assert(std::is_same<Bus, ScheduleableT>::value == false,
1105 "\nERROR: You cannot add a Bus to a precedence group as Buses do not support precedence directly. "
1106 "\n\tInstead, use Bus' inportsPrecede(event) or outportsSucceed(event) methods OR the >> operator.");
1107 addScheduable_<ScheduleableT::event_phase>(sched, scheds...);
1108 }
1109
1123 template<class DataT, SchedulingPhase PhaseT, class ...ArgsT>
1124 explicit EventGroup(PayloadEvent<DataT, PhaseT> & sched, ArgsT&...scheds) {
1125 addScheduable_<PhaseT>(sched, scheds...);
1126 }
1127
1128 };
1129
1143 template<class ScheduleableTypeB>
1144 ScheduleableTypeB & operator>>(const EventGroup & producers,
1145 ScheduleableTypeB & consumer)
1146 {
1147 for(auto & prod : producers) {
1148 prod->precedes(consumer);
1149 }
1150 return consumer;
1151 }
1152
1164 template<class ScheduleableTypeA>
1165 const EventGroup & operator>>(ScheduleableTypeA & producer,
1166 const EventGroup & consumers)
1167 {
1168 for(auto & cons : consumers) {
1169 producer.precedes(*cons);
1170 }
1171 return consumers;
1172 }
1173
1188 inline const EventGroup & operator>>(const EventGroup & producers,
1189 const EventGroup & consumers)
1190 {
1191 for(auto & prod : producers) {
1192 for(auto & cons : consumers) {
1193 sparta_assert(prod->getSchedulingPhase() == cons->getSchedulingPhase(),
1194 "The scheduling phase of '"
1195 << prod->getLabel() << "' phase '" << prod->getSchedulingPhase()
1196 << "' does not equal the scheduling phase of '"
1197 << cons->getLabel() << "' phase '" << cons->getSchedulingPhase()
1198 <<"'");
1199
1200 prod->precedes(cons);
1201 }
1202 }
1203 return consumers;
1204 }
1205
1206}
File that defines the Bus, BusSet and helper binding classes.
File that defines the Event class.
Contains a collection implementation of various compile-time metaprogramming and Type-Detection APIs ...
File that defines the PayloadEvent class.
File that defines the Port base class.
File that defines the Scheduleable class.
File that defines the SingleCycleUniqueEvent class.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
File that defines the UniqueEvent class.
Class that defines a Bus type.
Definition Bus.hpp:46
void inportsPrecede(EventT &event)
Make all inports precede the given event.
Definition Bus.hpp:194
void outportsSucceed(EventT &event)
Make all outports succeed the given event.
Definition Bus.hpp:209
Group a series of events together for precedence establishment.
EventGroup(ScheduleableT &sched, ArgsT &...scheds)
Construct the EventGroup.
EventGroup(PayloadEvent< DataT, PhaseT > &sched, ArgsT &...scheds)
Construct the EventGroup.
sparta::SchedulingPhase getSchedulingPhase() const
Get the scheduling phase of this event node.
Definition EventNode.hpp:93
virtual Scheduleable & getScheduleable()=0
Get the scheduleable associated with this event node.
Event is a simple class for scheduling random events on the Scheduler.
Definition Event.hpp:42
Scheduleable & getScheduleable() override
Get the scheduleable associated with this event node.
Definition Event.hpp:111
Used to set precedence between Scheduleable types across simulation.
DAG::GOPoint * getGOPoint() const
Used by the precedence rules.
Base class for all InPort types.
Definition Port.hpp:297
virtual Scheduleable & getScheduleable_()=0
Return the internally used Scheduleable for precedence.
Class to schedule a Scheduleable in the future with a payload, typed on both the data type and the sc...
Scheduleable & getScheduleable() override
Get the scheduleable associated with this event node.
void precedes(ScheduleableT &consumer, const std::string &reason="")
Have this SingleCycleUniqueEvent precede another.
A class that defines the basic scheduling interface to the Scheduler. Not intended to be used by mode...
void precedes(Scheduleable &consumer, const std::string &reason="")
Have this Scheduleable precede another.
SchedulingPhase getSchedulingPhase() const
Get the internal phase number.
An event that can only be schedule one cycle into the future.
A type of Event that uniquely schedules itself on the schedule within a single time quantum....
Macros for handling exponential backoff.
std::enable_if< std::is_base_of< EventNode, ScheduleableTypeA >::value, constGlobalOrderingPoint >::type & operator>>(ScheduleableTypeA &producer, const GlobalOrderingPoint &consumer)
Place a precedence between a Scheduleable object and a GlobalOrderingPoint.
SchedulingPhase
The SchedulingPhases used for events (Tick, Update, PortUpdate, etc)